# rm-rf.es

Limitar recursos a usuarios con Control Groups (Cgroups)

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:

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 :)

Salir de la versión móvil