En esta guía de cgroups Alojamiento Te mostraré específicamente cómo aíslo los recursos del servidor con grupos de control Linux para que los „vecinos ruidosos“ no ralenticen ningún servicio. Aprenderás cómo limito, priorizo y controlo de forma fiable la CPU, la RAM, la E/S en bloque y la red por sitio web, contenedor o usuario, de forma práctica y factible.
Puntos centrales
Los siguientes aspectos clave le guiarán en las decisiones y pasos más importantes.
- Aislamiento: Separa los procesos de forma limpia y domestica a los vecinos
- ControlarLimitar CPU, RAM, E/S y dispositivos de forma selectiva
- Prioridad: Pesar y proteger los servicios premium
- TransparenciaMedir la carga, utilizar alarmas y tendencias
- ActualizarDe v1 a v2 para una gestión clara
Cómo desconectan los cgroups los recursos del servidor
Los grupos de control clasifican los procesos en grupos y conectan estos grupos a controladores de recursos, lo que me permite Recursos por grupo. En un servidor compartido, esto evita que un solo sitio web consuma tiempo de CPU o llene la memoria hasta los topes. Para ello, establezco jerarquías en las que los grupos padres especifican límites superiores que heredan los grupos hijos. De este modo, la distribución de la carga es coherente y mantengo a raya los cuellos de botella. Con esto alivia notablemente el problema del „vecino ruidoso“ en particular, porque los picos fuertes se producen en pistas aisladas.
Controlador y sistema de archivos: las herramientas del oficio
El trabajo práctico comienza en el sistema de archivos cgroup en /sys/fs/cgroup, donde creo grupos y establezco límites, es decir, el concreto Sistema de control cuidar. Utilizo controladores como cpu, memory, blkio, cpuset y devices para asignar trozos de tiempo, cubrir RAM, ralentizar E/S, fijar núcleos o bloquear dispositivos. Combino estos bloques de construcción dependiendo de la aplicación: por ejemplo, aplicaciones que necesitan mucha memoria con límites de RAM, trabajos de construcción con pesos de CPU y bases de datos con anchos de banda de E/S. Es importante contar con un esquema de nomenclatura claro para poder encontrar rápidamente los grupos más adelante. De este modo, la administración es manejable y los cambios no se pierden de vista.
| Subsistema | Propósito |
|---|---|
| cpu / cpuacct | Asignar tiempo de CPU, Pesas y fijar cuotas |
| memoria | Limitar RAM, evitar muertes OOM |
| blkio | Acelerar la E/S de bloque, controlar la velocidad de lectura/escritura |
| cpuset | Asignación de núcleos de CPU y nodos NUMA |
| dispositivos | Permitir o bloquear el acceso al dispositivo |
| net_cls / net_prio | Marcar y priorizar las clases de red |
cgroups v1 vs. v2 en hosting
La antigua v1 separa los controladores en varios árboles, lo que rápidamente descubrí que era confuso en configuraciones grandes, así que decidí utilizar la función Conversión a la v2. cgroups v2 agrupa todo en un árbol claro y simplifica así la administración, la depuración y la herencia. Además, cpu.max, cpu.weight y memory.max en v2 proporcionan un conjunto coherente de palancas que funcionan bien juntas. Los orquestadores de contenedores también prefieren utilizar v2 porque la semántica está más estandarizada. Para entornos de alojamiento con muchos clientes, v2 es la opción más sencilla y fiable.
Control fino en cgroups v2: io, memoria, pids y PSI
En la v2, activo los controladores explícitamente por subárbol y así obtengo más control sobre la herencia. Sólo cuando los permito en el nodo padre puedo usarlos en grupos hijos - esto evita el crecimiento incontrolado y asegura políticas limpias.
# Activar controlador en nodo raíz para hijos
echo "+cpu +io +memory +pids" > /sys/fs/cgroup/cgroup.subtree_control
# Crear subgrupo y usarlo como espacio de trabajo
mkdir /sys/fs/cgroup/prod-web
Para I/O, uso el controlador io en v2 (en lugar de blkio). Establezco límites de ancho de banda o IOPS por dispositivo mediante especificaciones major:minor. Esto asegura que los registros, índices o copias de seguridad no obstruyan el disco.
Dispositivo # para /dev/sda (8:0) límite a 50 MiB/s de lectura, 20 MiB/s de escritura
echo "8:0 rbps=50M wbps=20M" > /sys/fs/cgroup/prod-web/io.max
# Asignar pesos relativamente (en lugar de hard cap, 100-10000, por defecto 100)
echo 500 > /sys/fs/cgroup/prod-web/io.weight
Configuro la memoria en dos etapas: memory.high ralentiza las cosas pronto, memory.max es una parada dura. También desactivo swap para los servicios críticos para que las latencias no exploten.
# Freno blando (límite blando) y tapa dura
echo $((400*1024*1024)) > /sys/fs/cgroup/prod-web/memory.high
echo $((512*1024*1024)) > /sys/fs/cgroup/prod-web/memory.max
# prohibir swap (0) o limitar (p.ej. 128 MiB)
echo 0 > /sys/fs/cgroup/prod-web/memory.swap.max
Utilizo el controlador pids para prevenir tormentas de bifurcaciones y mantener un límite superior de procesos e hilos por cliente - esto es una protección efectiva contra la mala configuración y el mal uso en entornos compartidos.
# Máximo 512 procesos/hilos en el grupo
echo 512 > /sys/fs/cgroup/prod-web/pids.max
Para el diagnóstico, utilizo cgroup.events y PSI (Pressure Stall Information) para cada grupo. PSI me muestra si la CPU, la memoria o la E/S se están agotando regularmente y provocan tiempos de espera. Esto es más valioso que la utilización pura porque hace visibles los cuellos de botella antes de que los usuarios los noten.
# Leer eventos y presiones
cat /sys/fs/grupo/prod-web/grupo.events
cat /sys/fs/cgroup/prod-web/cpu.pressure
cat /sys/fs/cgroup/prod-web/memory.pressure
cat /sys/fs/cgroup/prod-web/io.pressure
En situaciones de OOM, agrupo los kills específicamente con memory.oom.group para que los procesos relacionados (por ejemplo, worker + helper) se terminen de forma consistente en lugar de poner el sistema en un estado de parálisis parcial. Para ventanas de mantenimiento, congelo grupos brevemente con cgroup.freeze y luego los descongelo de nuevo - útil para migraciones de bases de datos o rollouts atómicos.
# Comportamiento de OOM en todo el grupo
echo 1 > /sys/fs/cgroup/prod-web/memory.oom.group
# Pausa / reanuda grupo
echo 1 > /sys/fs/cgroup/prod-web/cgroup.freeze
echo 0 > /sys/fs/cgroup/prod-web/cgroup.freeze
Paso a paso: Establecer límites en Linux
En los servidores con el kernel actual, activo cgroup v2 y luego creo grupos con límites superiores adecuados, lo que me permite Controlar directamente en el sistema. Los siguientes comandos muestran un ejemplo minimalista con límites de CPU y RAM. Selecciono cuotas de forma conservadora, controlo la carga y la ajusto en iteraciones. De esta forma, mantengo los tiempos de respuesta bajos sin cortar innecesariamente las fases de ráfaga útiles. La implementación permanece cerca del núcleo y funciona independientemente del software del panel.
# mount cgroup v2 (si no es automáticamente vía systemd)
mount -t cgroup2 none /sys/fs/cgroup
Crear el grupo #
mkdir /sys/fs/cgroup/prod-web
Asigna el proceso # (ejemplo: PID 1234) al grupo
echo 1234 > /sys/fs/cgroup/prod-web/cgroup.procs
Cuota CPU #: 100 ms de 200 ms => 50%
echo "100000 200000" > /sys/fs/cgroup/prod-web/cpu.max
# Límite duro de RAM: 512 MiB
echo $((512*1024*1024)) > /sys/fs/cgroup/prod-web/memory.max
Integración de Systemd y slices persistentes
En el día a día, dejo que systemd gestione el árbol cgroup. Así que los límites permanecen persistente y se documentan de forma transparente para cada servicio. Trabajo con slices (system.slice, user.slice, machine.slice) y defino mis propias jerarquías para clientes o roles. Utilizo archivos drop-in para establecer pesos y topes sin tener que escribir manualmente en /sys/fs/cgroup.
# Ejemplo: crea tu propio slice para servicios web.
cat > /etc/systemd/system/web.slice < /etc/systemd/system/php-fpm.service.d/10-slice.conf <<'EOF'
[Service]
Slice=web.slice
EOF
systemctl daemon-reload
systemctl restart php-fpm.service
Para pruebas ad-hoc, inicio procesos en ámbitos sin escribir archivos de unidad. Esto es adecuado para simular picos de carga o probar límites durante poco tiempo.
# Configure brevemente los recursos e inicie el proceso bajo control
systemd-run --scope -p CPUWeight=200 -p MemoryMax=512M \
-p IOReadBandwidthMax=/dev/sda:50M -p IOWriteBandwidthMax=/dev/sda:20M \
stress-ng --vm 1 --vm-bytes 300M --cpu 1
Los tiempos de ejecución de los contenedores gestionan sus propios subárboles (machine.slice) bajo systemd. La delegación es importante aquí: permito que el servicio de tiempo de ejecución gestione el subárbol (delegado) para que los pods/contenedores estén limpiamente aislados. Esto significa que las políticas del host y del contenedor no se solapan.
Utilizar los límites de los contenedores de forma segura
En entornos de contenedores, los cgroups actúan como guardarraíles invisibles que yo configuro mediante parámetros de tiempo de ejecución y, por tanto Contenedor a límites justos. Docker asigna las opciones -cpus, -memory y -blkio directamente a cgroups, por ejemplo, mientras que Kubernetes traduce las solicitudes y los límites a parámetros v2. La coherencia es crucial: los límites deben coincidir con la carga real para que los pods y contenedores no se aceleren innecesariamente o provoquen errores OOM. Mantengo los servicios productivos más ajustados, mientras que los trabajos de compilación o prueba sólo reciben más presupuesto si es necesario. Esto mantiene la previsibilidad de las implantaciones y evita que los despliegues se estanquen.
Evite el alojamiento compartido y los vecinos ruidosos
En entornos compartidos, establezco límites a nivel de paquete o suscripción para poder Equidad entre clientes. Paneles como Plesk facilitan esta tarea con un gestor de Cgroups que asigna CPU, RAM y E/S por suscripción y las muestra visualmente. También activo las notificaciones para reconocer y reaccionar a los picos de carga de forma inmediata. Si desea comparar Tenant-Isolation en detalle, puede echar un vistazo a Aislamiento de inquilinos lanzamiento. Esto significa que todos los sitios web siguen teniendo capacidad de respuesta, aunque a veces los clientes individuales generen más tráfico.
Establecer los límites adecuados: cgroups vs. ulimits
cgroups cap uso real, mientras que ulimits es principalmente por proceso o shell límites duros, que es la razón por la que uso Combinaciones específicamente. Para CPU, RAM y E/S establezco cgroups claros, para archivos o procesos abiertos controlo adicionalmente vía ulimit. Esto previene cuellos de botella en el descriptor de archivos y mantiene la utilización general bajo control. Si quieres refrescar los límites relacionados con el sistema, puedes encontrar un buen resumen en Límites de alojamiento. Ambos niveles juntos proporcionan los tornillos de ajuste más finos para una separación justa del cliente.
Supervisión y alerta
Sin medición, tomo decisiones a ciegas, así que ejecuto métricas permanentemente y establezco Umbrales para las alarmas. Herramientas como systemd-cgtop, ps, pidstat o Prometheus-Exporter me muestran en directo qué grupo está utilizando recursos actualmente. En los paneles, vinculo los cgroups a cuadros de mando que marcan los valores umbral y visualizan las tendencias. Las alertas por correo electrónico o chat me informan cuando los grupos superan los límites o se aceleran con frecuencia. Esto me permite identificar los cuellos de botella con antelación y ajustar los límites, ampliar el hardware u optimizar las rutas de código.
Control en profundidad: ratios, PSI y alarmas significativas
No sólo controlo la „utilización“, sino también la „presión“. En cgroups v2 leo cpu.stat (incluido throttled_us), memory.current, memory.high, memory.events, io.stat y los archivos de presión. Los utilizo para crear alarmas que reaccionen a la escasez de recursos en una fase temprana sin ser molestas durante los picos cortos.
- CPU: Alerta si throttled_us aumenta permanentemente y las latencias se deterioran al mismo tiempo. Entonces aumento CPUWeight o aflojo cpu.max.
- Memoria: memory.current cerca de memory.high es una señal de advertencia. Si memory.events informa frecuentemente de „high“, aumento high u optimizo las cachés.
- E/S: io.stat muestra rbps/wbps y tiempos de espera. Corrijo el estrangulamiento permanente mediante io.weight o dispositivos dedicados.
- PSI: La presión persistente „algo“/„lleno“ es un indicador de que las cargas de trabajo esperan recursos con regularidad. Lo utilizo para planificar la capacidad.
Buenas prácticas para una configuración limpia
Siempre empiezo con valores conservadores, porque las tapas demasiado afiladas en horas punta Actuación costes. A continuación, cargo específicamente el servicio con benchmarks como ab, siege o wrk para aumentar gradualmente las cuotas. En el caso de los hosts multiaplicación, organizo los grupos en rebanadas para dar prioridad a los servicios importantes sin privar a los demás de todo. Establezco los límites de E/S de forma que los picos cortos se cuelen, pero las fases más largas se ralenticen. Las revisiones periódicas evitan que los límites queden obsoletos mientras cambian los perfiles de carga.
Migración de v1 a v2: así procedo yo
Planifico el cambio como una actualización de infraestructura normal. En primer lugar, compruebo si el kernel y systemd v2 están activados por defecto. Si es necesario, comienzo con los parámetros de arranque adecuados y valido que el árbol unificado esté activo. A continuación, pruebo todas las integraciones (paneles, agentes, copias de seguridad, tiempo de ejecución de contenedores) en un entorno de ensayo.
- Detección: mount | grep cgroup2 o systemd-cgls me muestra si v2 se está ejecutando.
- Parámetros de arranque: Si es necesario, configuro cgroup_no_v1=all u opciones unificadas para que sólo esté activa la v2.
- Mapeo de controladores: blkio se convierte en io; sustituyo algunas características de v1 (net_cls/prio) por control de tráfico con clasificadores cgroup o BPF.
- Migrar políticas: Usar pesos en lugar de cuotas rígidas, introducir memory.high, limitar swap por separado.
- Personalizar la monitorización: Transfiere nuevas rutas y campos (cgroup.events, cpu.stat) a los cuadros de mando.
Añadir aislamiento de procesos
Los cgroups resuelven el problema de los recursos, pero para el acceso al sistema separo adicionalmente Nombre espacios y vistas de archivos. Chroot, CageFS, namespaces y jails sellan rutas, objetos del kernel y dispositivos para que los clientes no se puedan alcanzar entre sí. Esta capa de protección es una adición útil a los límites porque reduce el radio de daño y la superficie de ataque. Puedes encontrar una visión concisa de las variantes más importantes aquí: Aislamiento de procesos. En combinación con cgroups, se crea una separación de clientes limpia para configuraciones de alojamiento de cualquier tamaño.
Escenarios prácticos y puesta a punto
Durante los picos de tráfico en las configuraciones de CMS, le doy a la CPU un respiro a corto plazo, pero mantengo la RAM dura para que pueda Seguridad contra fallos OOM. Para las tiendas que hacen un uso intensivo de datos, regulo blkio para que la indexación no ralentice todos los demás procesos de lectura. Vinculo los procesos de análisis o de los trabajadores a unos pocos núcleos con cpuset para que los trabajadores web puedan responder sin interrupciones en los demás núcleos. Muevo los trabajos en segundo plano a grupos con menor peso de CPU para que las peticiones del frontend sigan siendo fluidas. Para los clientes dedicados, permito que memory.min asegure una pequeña base de RAM garantizada para una aplicación premium.
Solución de problemas y tropiezos típicos
Algunos patrones de error se repiten. Presto atención a los siguientes puntos para ahorrar tiempo en la solución de problemas:
- Cuotas de CPU demasiado duras: El estrangulamiento permanente aumenta la latencia. Es mejor trabajar con cpu.weight y cpu.max solo como cinturón de seguridad.
- Presión de memoria sin OOM: memory.high limita eficazmente, pero si la caché de páginas se limita demasiado, aumentan las latencias de E/S. Ajusta y recorta las cachés de forma selectiva.
- Efectos del intercambio: Demasiado swap ralentiza los sistemas. Por lo tanto, opere los servicios críticos con memory.swap.max=0, pero asegure todo el sistema con un búfer pequeño.
- Subárboles olvidados: Sin una entrada en cgroup.subtree_control, los límites hijos no se aplican. Active siempre primero el controlador en el nodo padre.
- Grupo equivocado: Los procesos a veces terminan en la rebanada equivocada. Lo compruebo con systemd-cgls y corrijo las opciones de la unidad de servicio (Slice=, Delegate=).
- pids.max demasiado bajo: Daemon con muchos hilos de trabajo falla silenciosamente. Seleccione un búfer generoso y realice un seguimiento en la monitorización.
- Límites de E/S por dispositivo: Para RAID/LVM, utilice el major:minor correcto o establezca límites para los dispositivos de bloque visibles que la carga de trabajo utiliza realmente.
- Priorización de la red: net_cls/prio son heredados de v1. En v2, confío en el control del tráfico con clasificadores cgroup o BPF para controlar los flujos de tráfico.
Funciones, perfiles y modelos de equidad
Me gusta trabajar con perfiles de servicio claros que almaceno como plantillas y despliego automáticamente:
- Premium (Oro): Altos pesos de CPU y E/S, memoria.min para base garantizada, límite duro de memoria.max con reserva suficiente.
- Estándar (plata): Pesos medios, io.weight moderado, memory.high ligeramente por debajo del pico para evitar el desbordamiento de la caché.
- Fondo (Bronce): Bajos pesos CPU/I/O, cpu.max estricto para desacoplar cargas de trabajo interactivas.
También reservo núcleos y RAM para el host y la infraestructura central (monitorización, registro, copia de seguridad). Esto evita que los clientes se traguen la sobrecarga del sistema. En el caso de los hosts NUMA, utilizo cpuset para mantener la memoria local en los núcleos en uso, lo que reduce los picos de latencia en los servicios intensivos en memoria.
Breve resumen
Con cgroups establezco guardarraíles claros para CPU, RAM, E/S y red, lo que me permite Equidad entre servicios y amortiguar los cuellos de botella. La arquitectura estandarizada de cgroups v2 me facilita la planificación, el funcionamiento y la resolución de problemas en comparación con v1. En contenedores, alojamiento compartido y entornos mixtos, puedo mantener a raya a los „vecinos ruidosos“ y proteger las cargas de trabajo críticas. La supervisión y las útiles alarmas me dan señales tempranas cuando los límites ya no se ajustan a los perfiles de carga. Si combinas cgroups con aislamiento de procesos, ulimits y un ajuste limpio, puedes construir una plataforma de alojamiento fiable que funcione de forma consistente y trate a los clientes de forma justa.


