Limitação de recursos com o groups – parte 2

cgroups-2_abertura

Na primeira parte da limitação de recursos com o uso de cgroups foram vistas as restrições de tempo de processamento e também da quantidade de processadores disponíveis a um determinado processo, ou grupo de processos. Agora, tal qual prometido, é a vez da memória.

Mais um grupo de controle

Assim como feito na primeira parte, é necessário criar um novo grupo, só que desta vez relacionado ao controlador “memory”:

$ sudo cgcreate -a giovanni:giovanni -t giovanni:giovanni -g memory:/limitado

É quase o mesmo exemplo da primeira parte, com a definição do meu próprio usuário como administrador e também executor dos processos neste grupo que, claro, chamei de “limitado”… 🙂

Limitando o uso de memória

A limitação da memória pode ser aplicável somente para a RAM disponível — memória física — ou então para toda a memória que está disponível — memória física + memória virtual — e neste caso, aliás, a documentação recomenda que você ajuste primeiro toda a memória disponível para então limitar a memória RAM para evitar problemas.

Um programa de teste

Ao invés de um programa mal escrito e bugado¹ como o da primeira parte, algo um pouco mais bonito:

Compile-o com:

$ cc -o memory memory.c

E por enquanto deixe-o quieto.

Mas o que este programa faz? Simples, ele aloca blocos de memória, originalmente em blocos de 1GiB, depois em blocos de 1MiB e no final de 1KiB até exaurir toda a memória (física e virtual) e morrer por falta de memória.

Atenção, não execute este programa fora de um grupo de controle!

Configurando

Sendo este programa um voraz consumidor de memória é melhor limitá-lo com o mínimo necessário, apenas para executá-lo sem acabar com os recursos do computador no processo:

$ cgset -r memory.limit_in_bytes=16M limitado
$ cgset -r memory.memsw.limit_in_bytes=32M limitado

O primeiro comando limitará em 16MiB a quantidade total de memória dentro do grupo enquanto que o segundo limitará em 32MiB a memória virtual. Aqui é importante ressaltar que o valor definido em memsw.limit_in_bytes deverá conter, no mínimo, o valor definido em limit_in_bytes.

Sim, o valor está em bytes mas é possível usar K, M e G para definir quantidades em kilobyte, megabyte, gigabyte.

Testado 1,2,3

Acontece que o teste mais óbvio que se poderia pensar fazer neste caso não funcionará:

$ cgexec -g memory:limitado free
         total     used     free   shared   buff/cache   available
Mem:   2025672   506328   208780   107076      1310564     1171852
Swap:  2059260     1044  2058216

Ué? Simples, acontece que o free pega os valores das tabelas dentro da estrutura do “/proc” — E no caso específico dos contêineres é justamente aqui que o Linux Namespaces entra em ação fazendo a correta alteração dos valores dentro deste diretório.

Sendo assim é hora de executar o memory para “ver o que acontece”:

$ time cgexec -g memory:limitado ./memory
Morto
real    0m39,338s
user    0m1,372s
sys     0m8,892s

O que aconteceu? Simples, o programa realmente consumir toda a memória que foi reservada para ele, os 32MiB, até que ele acabou sendo encerrado por falta de memória. Mas como saber que houve realmente uma limitação da memória? Observe esta imagem:

cgroups-2_memory_1024

O limite foi redefinido em 1GiB para facilitar a identificação, já que o valor de ~50% é bem mais fácil de enxergar que algo em torno de 1%. 🙂

(¹) Havia um erro no programa de geração dos números primos

Considerações finais

Claro, optei por exemplos simples de limitação de processamento e de consumo de memória mas estes não são as únicas funcionalidades disponíveis; a lista é bastante interessante incluindo dispositivos do sistema (devices), operações de E/S (blkio) , rede (net_cls e net_prio) etc.

E algumas considerações importantes quanto ao uso dos cgroups:

  1. Os valores definidos dentro de um grupo de controle podem ser alterados com os processos associados a eles em execução.
  2. Dentro de “/sys/fs/cgroups” é possível conhecer todos os controladores disponíveis e os parâmetros disponíveis em cada um deles e dentro do diretório dos controladores cada grupo criado replica esta mesma organização;
  3. É possível associar grupos de controle a processos que já estejam em execução através do comando cgclassify, basta indicar o grupo desejado, o PID do processo/dos processos e, claro, se ser o executor dele (ou então o “root”) e
  4. Para tornar as definições dos grupos de controle permanente utilize o cgsnapshot para criar o arquivo “/etc/cgconfig.conf”. Mas cuidado pois algumas distribuições fazem uso dos cgroups.

E para fechar, os cgroups não servem apenas para restrição de recursos, também funcionam para contabilização de recursos como é o caso do cpuacct que registra automaticamente o tempo de processamento dentro de um grupo de controle.

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s