Los grupos de control (cgroups) son una funcionalidad del kernel Linux disponible a partir de la versión 2.6.24 que permite limitar y distribuir el uso de recursos de sistema como la CPU, memoria, red o disco entre determinados usuarios, grupos o procesos del sistema. Con esta funcionalidad podemos establecer con bastante granularidad el uso que cada usuario, grupo o proceso puede hacer de los recursos de hardware disponibles.
Los recursos que podemos gestionar se configuran a través de subsistemas. Algunos de los disponibles son los siguientes:
- blkio: limita la entrada/salida a dispositivos de almacenamiento.
- cpu: a través del scheduler controla el acceso a las CPU.
- memory: establece límites en el uso de memoria.
- net_prio: este subsistema permite establecer prioridades dinámicas en el tráfico de las interfaces de red.
La documentación de RHEL sobre cgroups es bastante completa, os recomiendo echarle un vistazo para profundizar sobre el tema. En esta entrada vamos a ir al grano y ver algunas de las posibilidades que nos ofrece esta funcionalidad del kernel.
Instalación de cgroups
En Red Hat y derivados es tan sencillo como instalar el paquete libcgroup:
# yum install libcgroup
Configuración de cgroups
Una vez instalado, tenemos que saber que toda la jerarquía de subsistemas de control de recursos se montan automáticamente en /cgroup al arrancar el demonio cgconfig:
# chkconfig cgconfig on # service cgconfig start
Este demonio monta estos subsistemas y activa los grupos de recursos que hemos especificado en el archivo de configuración /etc/cgconfig.conf
, en el que por defecto únicamente aparece la configuración de montado de los subsistemas:
mount { cpuset = /cgroup/cpuset; cpu = /cgroup/cpu; cpuacct = /cgroup/cpuacct; memory = /cgroup/memory; devices = /cgroup/devices; freezer = /cgroup/freezer; net_cls = /cgroup/net_cls; blkio = /cgroup/blkio; }
Con el comando lscgroups
podemos listar los subsistemas activos:
# lscgroup cpuset:/ cpu:/ cpuacct:/ memory:/ devices:/ freezer:/ net_cls:/ blkio:/
Justo debajo del bloque mount
del archivo de configuración /etc/cgconfig.conf
es donde debemos especificar nuestros grupos de limitación. En el siguiente ejemplo añadimos un grupo llamado «iolimit» en el cual especificamos que los usuarios, grupos o procesos que estén «enganchados» a él tendrán una limitación de 10 MB/s lectura en el disco «sda»:
$ grep sda /proc/partitions | head -1 8 0 2774016 sda
group iolimit { blkio { blkio.throttle.read_bps_device="8:0 10485760"; } }
Si ahora reiniciamos el servicio veremos que nuestro grupo «iolimit» está asociado al subsistema blkio:
# service cgconfig restart # lscgroup cpuset:/ cpu:/ cpuacct:/ memory:/ devices:/ freezer:/ net_cls:/ blkio:/ blkio:/iolimit
Igual que hemos hecho un grupo de limitación de MB/s podríamos hacer otro de IOPS, ciclos de CPU, ancho de banda, memoria, etc. También se puede hacer un grupo combinando varios subsistemas y parámetros. Si navegáis por /cgroup/*
podréis ver toda la parametrización posible.
Por el momento no le hemos dicho qué usuarios o grupos de sistema deben tener esta limitación de I/O, para ello se utiliza el demonio cgred y el archivo de configuración /etc/cgrules.conf
:
# chkconfig cgred on # service cgred start
El archivo de configuración es muy sencillo. Indicamos usuario/grupo de sistema, subsistema y grupo de limitación:
# Example: # #@student cpu,memory usergroup/student/ #peter cpu test1/ #% memory test2/ foo blkio iolimit/
Probando cgroups
Según la configuración anterior hemos establecido una limitación de 10MB/s al usuario foo contra el disco /dev/sda así que hacemos la prueba para confirmar el correcto funcionamiento:
$ sudo hdparm --direct -t /dev/sda [sudo] password for foo: /dev/sda: Timing O_DIRECT disk reads: 32 MB in 3.19 seconds = 10.03 MB/sec
¡Funcionando! si hacéis la prueba con «dd» aseguraos de utilizar la flag direct oflag=direct
para hacer bypass de los buffers y cachés de SO.
Si lo que queremos es aplicar la limitación a un proceso concreto en lugar de a un usuario podemos lanzar el comando con cgexec
del siguiente modo:
# cgexec -g SUBSISTEMA:GRUPO COMANDO
En el siguiente ejemplo podemos ver la diferencia de ejecutar el comando con y sin la limitación como root:
[root@lab1 ~]# cgexec -g blkio:iolimit hdparm --direct -t /dev/sda /dev/sda: Timing O_DIRECT disk reads: 32 MB in 3.20 seconds = 10.02 MB/sec [root@lab1 ~]# hdparm --direct -t /dev/sda /dev/sda: Timing O_DIRECT disk reads: 278 MB in 3.01 seconds = 92.30 MB/sec
La configuración que he puesto en este artículo es sólo la punta del iceberg de las posibilidades que ofrece cgroup. Para más información empapaos la documentación :)