¿Cómo crear un usuario con uso limitado de RAM?

45

Entonces tengo 4 GB de RAM + 4GB de intercambio. Quiero crear un usuario con RAM e intercambio limitados: 3 GB de RAM y 1 GB de intercambio. ¿Es posible tal cosa? ¿Es posible iniciar aplicaciones con RAM limitada e intercambiar disponibles sin crear un usuario separado (y sin instalar ninguna aplicación especial, teniendo solo una configuración predeterminada del servidor Debian / CentOS y sin usar sudo)?

Actualizar:

Entonces abrí terminall y escribí en él el comando ulimit : ulimit -v 1000000que será como una 976,6Mblimitación. Luego llamé ulimit -ay vi que la limitación está "activada". Luego comencé un script bash que compila e inicia mi aplicación nohup, una larga nohup ./cloud-updater-linux.sh >& /dev/null & ... pero después de un tiempo vi:

ingrese la descripción de la imagen aquí

(lo cual estaría bien si no se aplicaran limitaciones: descargó una gran biblioteca y comenzó a compilarla).

¿Pero pensé que apliqué limitaciones al shell y a todos los procesos iniciados con / desde él con ulimit -v 1000000? ¿Qué me equivoqué? ¿Cómo hacer que un terminal y todos los subprocesos que lanza estén limitados en el uso de RAM?

myWallJSON
fuente
1
No puede imponer restricciones de memoria a un usuario como un todo, solo en cada proceso. Y no puede distinguir entre RAM y uso de intercambio. Si desea un control más preciso, ejecute los procesos del usuario en una máquina virtual.
Gilles 'SO- deja de ser malvado'
@Gilles está bastante seguro de que las máquinas virtuales solo usan cgroups y espacios de nombres, o derivados de
RapidWebs
@RapidWebs no, no lo hacen. Simplemente emulan la cantidad predefinida de RAM y el SO huésped decide cómo asignarla a los procesos.
Ruslan
Los contenedores (no las máquinas virtuales) usan cgroups para limitar el uso de memoria. Limitar la memoria virtual no es una buena idea; Un proceso puede usar mucha memoria virtual, pero solo puede usar un poco de RAM. Por ejemplo, mi sistema tiene 34359738367 kB de memoria virtual asignada, pero mucho menos memoria RAM.
ctrl-alt-delor

Respuestas:

65

ulimitestá hecho para esto. Puede configurar valores predeterminados para ulimitcada usuario o por grupo en

/etc/security/limits.conf

ulimit -v KBYTESestablece el tamaño máximo de memoria virtual. No creo que puedas dar una cantidad máxima de intercambio. Es solo un límite en la cantidad de memoria virtual que el usuario puede usar.

Entonces limits.conftendría la línea (hasta un máximo 4Gde memoria)

luser  hard  as   4000000

ACTUALIZACIÓN - CGroups

Los límites impuestos por ulimity limits.confes por proceso. Definitivamente no estaba claro en ese punto.

Si desea limitar la cantidad total de memoria que utiliza un usuario (que es lo que solicitó). Desea usar cgroups .

En /etc/cgconfig.conf:

group memlimit {
    memory {
        memory.limit_in_bytes = 4294967296;
    }
}

Esto crea un cgroupque tiene un límite máximo de memoria de 4GiB.

En /etc/cgrules.conf:

luser   memory   memlimit/

Esto hará que todos los procesos ejecutados luserse ejecuten dentro de los memlimitcgroups creados en cgconfig.conf.

utopía
fuente
¿Se puede configurar tal cosa useradd?
myWallJSON
44
@myWallJSON No directamente, pero puede agregarlo inmediatamente a limits.conf, o puede configurar un grupo con ciertos límites en limits.conf y agregar usuarios a ese grupo.
utopiabound
1
¡Eso es genial! ¡No sabía que podías hacer esto! Gran respuesta +1
Yanick Girouard
1
@utopiabound: Actualicé mi Q con algunos datos que traté de usar ulimit.
myWallJSON
1
@ f.ardelian Actualice el núcleo. ¡Aquí hay un artículo sobre cómo hacer eso!
Daniel C. Sobral
4

No puede limitar el uso de memoria en el nivel de usuario, ulimit puede hacerlo pero para un solo proceso.

Incluso con el uso de límites por usuario /etc/security/limits.conf, un usuario puede usar toda la memoria ejecutando múltiples procesos.

Si realmente desea limitar los recursos, debe usar una herramienta de administración de recursos, como rcapd utilizada por proyectos y zonas en Solaris.

Hay algo que parece proporcionar características similares en Linux que podrías investigar: cgroups .

jlliagre
fuente
Bueno, supongo que establecer un límite en el shell de inicio de sesión de los usuarios o algo así podría interpretarse como "establecer un límite para el usuario", ya que todos los procesos heredarían de ese shell.
amn
1
@amn No lo hará. Un usuario podría simplemente abrir un nuevo shell de inicio de sesión para solucionar dicho límite.
jlliagre
Correcto, eso invalida mi suposición bien.
amn
4

cgroupsson la forma correcta de hacer esto, como lo han señalado otras respuestas. Lamentablemente, no hay una solución perfecta para el problema, como veremos a continuación. Hay muchas formas diferentes de establecer límites de uso de memoria de cgroup. La forma en que uno hace que la sesión de inicio de sesión de un usuario forme parte automáticamente de un grupo c varía de un sistema a otro. Red Hat tiene algunas herramientas, y también systemd .

memory.memsw.limit_in_bytesy memory.limit_in_bytesestablecer límites que incluyen y no incluyen swap, respectivamente. La desventaja memory.limit_in_byteses que cuenta los archivos almacenados en caché por el núcleo en nombre de los procesos en el cgroup contra la cuota del grupo. Menos almacenamiento en caché significa más acceso al disco, por lo que posiblemente esté renunciando a un cierto rendimiento si el sistema de otra manera tuviera algo de memoria disponible.

Por otro lado, memory.soft_limit_in_bytespermite que cgroup supere la cuota, pero si se invoca al asesino OOM del núcleo, entonces los cgroup que superaron sus cuotas se eliminan primero, lógicamente. Sin embargo, la desventaja de esto es que hay situaciones en las que se necesita algo de memoria de inmediato y no hay tiempo para que el asesino de OOM busque procesos para matar, en cuyo caso algo podría fallar antes de que los procesos del usuario con exceso de cuota delicado.

ulimit, sin embargo, es absolutamente la herramienta incorrecta para esto. ulimit pone límites al uso de memoria virtual, lo que casi seguro no es lo que desea. Muchas aplicaciones del mundo real usan mucha más memoria virtual que la memoria física. La mayoría de los tiempos de ejecución recolectados de basura (Java, Go) funcionan de esta manera para evitar la fragmentación. Un programa trivial de "hola mundo" en C, si se compila con un desinfectante de direcciones, puede usar 20 TB de memoria virtual. Asignadores que no dependen sbrk, como jemalloc (que es el asignador predeterminado para Rust) o tcmalloc, también tendrá un uso de memoria virtual sustancialmente superior al uso físico. Para mayor eficiencia, muchas herramientas crearán archivos mmap, lo que aumenta el uso virtual pero no necesariamente el uso físico. Todos mis procesos de Chrome utilizan 2 TB de memoria virtual cada uno. Estoy en una computadora portátil con 8 GB de memoria física. Cualquier forma en que uno intentara establecer cuotas de memoria virtual aquí podría romper Chrome, forzar a Chrome a deshabilitar algunas características de seguridad que dependen de la asignación (pero no usar) grandes cantidades de memoria virtual, o ser completamente ineficaz para evitar que un usuario abuse del sistema .

Adam Azarchs
fuente