Gerenciando Recursos com Grupos de Controle

Explica como os grupos de controle organizam processos, como systemd aplica políticas de recursos e quando gerenciar cgroups manualmente.

Os grupos de controle, chamados de cgroups, são um recurso do kernel do Oracle Linux que organiza serviços do systemd e, se necessário, processos individuais (PIDs), em grupos hierárquicos para alocar recursos do sistema, como CPU, memória e E/S.

Por exemplo, se você tiver identificado três processos que precisam receber tempo de CPU em uma proporção de 150:100:50, poderá criar três cgroups, cada um com um peso de CPU correspondente a um dos três valores na proporção, e atribuir o processo apropriado a cada cgroup.

Importante

Use systemd para configurar cgroups.

A criação manual de diretórios cgroup no sistema de arquivos virtual /sys/fs/cgroup (conforme discutido neste tópico) pode ser útil para ilustrar conceitos subjacentes. No entanto, ao usar essa abordagem para cenários específicos, como depuração ou teste temporários. Para a maioria dos casos de uso, use systemd para configurar o cgroups para garantir o gerenciamento de recursos correto e persistente.

Por padrão, systemd cria uma cgroup para o seguinte:

  • Cada serviço systemd configurado no host.

    Por exemplo, um servidor pode ter o grupo de controle NetworkManager.service para agrupar processos pertencentes ao serviço NetworkManager e o grupo de controle firewalld.service para agrupar processos pertencentes ao serviço firewalld e assim por diante.

  • Cada usuário (UID) no host.

A funcionalidade cgroup é montada como um sistema de arquivos virtual em /sys/fs/cgroup. Cada cgroup tem um diretório correspondente no sistema de arquivos /sys/fs/cgroup. Por exemplo, o cgroups criado pelo systemd para os serviços que ele gerencia pode ser visto executando o comando ls -l /sys/fs/cgroup/system.slice | grep ".service", conforme mostrado no seguinte bloco de código de amostra:

ls -l /sys/fs/cgroup/system.slice | grep ".service"
            ...root root 0 Mar 22 10:47 atd.service
            ...root root 0 Mar 22 10:47 auditd.service
            ...root root 0 Mar 22 10:47 chronyd.service
            ...root root 0 Mar 22 10:47 crond.service
            ...root root 0 Mar 22 10:47 dbus-broker.service
            ...root root 0 Mar 22 10:47 dtprobed.service
            ...root root 0 Mar 22 10:47 firewalld.service
            ...root root 0 Mar 22 10:47 httpd.service
            ...

Você também pode criar cgroups personalizado criando diretórios no sistema de arquivos virtual /sys/fs/cgroup e atribuindo IDs de processo (PIDs) a diferentes cgroups de acordo com os requisitos do sistema. No entanto, a prática recomendada é usar systemd para configurar cgroups em vez de criar a cgroups manualmente em /sys/fs/cgroup.

Para obter o método recomendado de gerenciamento de cgroups por meio de systemd, consulteUsando Systemd para Gerenciar Grupos de Controle.

Duas versões de grupos de controle estão disponíveis no kernel do Linux.

Grupos de controle versão 1 (cgroups v1)

Fornece uma hierarquia de controladores por recurso. Cada recurso (CPU, memória, E/S, etc.) tem sua própria árvore de grupo de controle. Isso pode dificultar a coordenação entre os recursos. Usa uma API legada. Agora considerado obsoleto, mas disponível para compatibilidade em sistemas suportados.

Grupos de controle versão 2 (cgroups v2)

Usa uma hierarquia unificada e única para todos os controladores, permitindo uma melhor coordenação entre recursos e um gerenciamento mais simples. Usa uma API moderna e simplificada. Esta é a implementação preferida e ativamente desenvolvida.

A tabela a seguir resume a disponibilidade por versão do Oracle Linux:

Suporte a Versão cgroups da Versão Oracle Linux
Versão do Oracle Linux cgroups v1 cgroups v2
Oracle Linux 8 Disponível (padrão) Disponível (ativar manualmente)
Oracle Linux 9 Disponível (compatibilidade) Disponível (padrão)
Oracle Linux 10 Não disponível (obsoleto) Disponível (padrão)

Para obter mais informações sobre grupos de controle, revise as páginas manuais cgroups(7) e sysfs(5).

Ativar cgroups v2 no Oracle Linux 8

  1. Verifique as montagens atuais.
    sudo mount -l | grep cgroup

    Se a saída já mostrar cgroup2 no /sys/fs/cgroup, nenhuma ação adicional será necessária.

  2. Adicione o parâmetro de inicialização de hierarquia unificada.
    sudo grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=1"

    O comando anexa systemd.unified_cgroup_hierarchy=1 a cada entrada do kernel para que a versão 2 seja montada na inicialização.

  3. Reinicialize para aplicar a alteração.
  4. Verifique se o cgroups v2 está montado.
    sudo mount -l | grep cgroup

    Procure cgroup2 on /sys/fs/cgroup na saída.

Verifique os cgroups v2 com o Oracle Linux 9 e Oracle Linux 10

Confirme o ponto de montagem.
sudo mount -l | grep cgroup
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,seclabel,nsdelegate,memory_recursiveprot)

Sobre Controladores de Recursos do Kernel

Os grupos de controle gerenciam o uso de recursos através de kernel resource controllers. Um controlador de recursos do kernel representa um único recurso, como tempo de CPU, memória, largura de banda de rede ou E/S de disco.

Para identificar controladores de recursos montados no sistema, verifique o conteúdo do arquivo /procs/cgroups, por exemplo, execute:

less /proc/cgroups
#subsys_name    hierarchy       num_cgroups     enabled
cpuset  0       103     1
cpu     0       103     1
cpuacct 0       103     1
blkio   0       103     1
memory  0       103     1
devices 0       103     1
freezer 0       103     1
net_cls 0       103     1
perf_event      0       103     1
net_prio        0       103     1
hugetlb 0       103     1
pids    0       103     1
rdma    0       103     1
misc    0       103     1

Para obter uma explicação detalhada dos controladores de recursos do kernel do cgroups, consulte a página manual cgroups(7).

Sobre o Sistema de Arquivos do Grupo de Controle

A funcionalidade cgroup é montada como um sistema de arquivos hierárquico no /sys/fs/cgroup.

O diretório /sys/fs/cgroup também é chamado de grupo de controle raiz.

O conteúdo do diretório do grupo de controle raiz varia ligeiramente dependendo da versão montada, mas em sistemas que usam cgroups v2 você normalmente vê entradas semelhantes às seguintes:

ls /sys/fs/cgroup
cgroup.controllers      cpuset.mems.effective  memory.stat
cgroup.max.depth        cpu.stat               misc.capacity
cgroup.max.descendants  dev-hugepages.mount    sys-fs-fuse-connections.mount
cgroup.procs            dev-mqueue.mount       sys-kernel-config.mount
cgroup.stat             init.scope             sys-kernel-debug.mount
cgroup.subtree_control  io.pressure            sys-kernel-tracing.mount
cgroup.threads          io.stat                system.slice
cpu.pressure            memory.numa_stat       user.slice
cpuset.cpus.effective   memory.pressure
Você pode usar o comando mkdir para criar subdiretórios cgroup dentro do grupo de controle raiz. Por exemplo, você pode criar os seguintes subdiretórios cgroup:
  • /sys/fs/cgroup/MyGroups/

  • /sys/fs/cgroup/MyGroups/cgroup1

  • /sys/fs/cgroup/MyGroups/cgroup2

Observação

A melhor prática de design é que o cgroups filho tenha pelo menos 2 níveis de profundidade no /sys/fs/cgroup. Os exemplos na lista anterior seguem esta prática usando o primeiro grupo filho, MyGroups, como pai que contém os diferentes cgroups necessários para o sistema.

Cada cgroup na hierarquia contém os seguintes arquivos:

cgroup.controllers

Esse arquivo somente leitura lista os controladores disponíveis no cgroup atual. O conteúdo desse arquivo corresponde ao conteúdo do arquivo cgroup.subtree_control no cgroup pai.

cgroup.subtree_control

Esse arquivo contém os controladores no arquivo cgroup.controllers que estão ativados para o cgroups filho imediato do cgroup.

Quando um controlador (por exemplo, pids) está presente no arquivo cgroup.subtree_control, os arquivos de interface do controlador correspondentes (por exemplo, pids.max) são criados automaticamente nos filhos imediatos do cgroup atual.

Para obter uma amostra de procedimento que cria grupos filhos nos quais você pode implementar o gerenciamento de recursos de um aplicativo, consulte Definindo o Peso da CPU para Regulamentar a Distribuição do Tempo da CPU.

Para remover uma cgroup, certifique-se de que a cgroup não contenha outros grupos filhos e, em seguida, remova o diretório. Por exemplo, para remover o grupo filho /sys/fs/cgroup/MyGroups/cgroup1, você pode executar o seguinte comando:

sudo rmdir /sys/fs/cgroup/MyGroups/cgroup1

Sobre Modelos de Distribuição de Recursos

Os seguintes modelos de distribuição fornecem maneiras de implementar o controle ou a regulamentação na distribuição de recursos para uso pelo cgroups v2:

Dimensões

Neste modelo, os pesos de todos os grupos de controle são totalizados. Cada grupo recebe uma fração do recurso com base na proporção do peso do grupo em relação ao peso total.

Considere 10 grupos de controle, cada um com um peso de 100 para um total combinado de 1000. Nesse caso, cada grupo pode usar um décimo de um recurso especificado.

O peso geralmente é usado para distribuir recursos sem monitoramento de estado. Para aplicar esse recurso, a opção CPUWeight é usada.

Limites

Neste modelo, um grupo pode usar até o valor configurado de um recurso. Se um recurso, como o uso de memória para um processo, exceder o limite, o kernel poderá interromper o processo com uma mensagem de falta de memória (oom).

Também é possível fazer commit em excesso dos recursos para que a soma dos limites dos subgrupos possa exceder o limite do grupo pai. O comprometimento excessivo pressupõe que os recursos de todos os subgrupos provavelmente não atingirão seus limites ao mesmo tempo.

Para implementar esse modelo de distribuição, a opção MemoryMax é frequentemente usada.

Proteções

Neste modelo, um grupo recebe um limite protegido. Se o uso de recursos do grupo permanecer na quantidade protegida, o kernel não poderá privar o grupo do uso do recurso em favor de outros grupos que estejam competindo pelo mesmo recurso. Neste modelo, um comprometimento excessivo de recursos é permitido.

Para implementar esse modelo, a opção MemoryLow geralmente é usada.

Alocações

Neste modelo, um valor absoluto específico é alocado para o uso de tipo finito de recursos, como orçamento em tempo real.

Gerenciando cgroups v2 Usando sysfs

Mostra como criar e ajustar hierarquias cgroups v2 diretamente no /sys/fs/cgroup para solução de problemas ou testes temporários.

Importante

Use systemd para lidar com todo o gerenciamento de recursos sempre que possível. Para obter mais informações, consulte Usando o Systemd para Gerenciar Grupos de Controle.

Os exemplos fornecidos aqui fornecem o contexto para ações que o systemd executa em um sistema e mostram a funcionalidade fora do systemd. As informações fornecidas podem ser úteis ao depurar problemas com o cgroups.

O procedimento de exemplo envolve a alocação de tempo de CPU entre cgroups que cada um tem diferentes PIDs de aplicativo designados a eles. Os valores de tempo de CPU e PID do aplicativo são definidos nos arquivos cpu.weight e cgroup.procs de cada grupo.

O exemplo também inclui as etapas necessárias para garantir que o controlador cpu e seus arquivos associados, incluindo o arquivo cpu.weight, estejam disponíveis no cgroups que você precisa criar em /sys/fs/cgroup.

Preparando o Grupo de Controle para Distribuição de Tempo de CPU

Este procedimento descreve como preparar manualmente um grupo de controle para gerenciar a distribuição do tempo de CPU. Observe que a abordagem recomendada para configurar grupos de controle é usar o systemd.

  1. Verifique se o controlador cpu está disponível na parte superior da hierarquia, no grupo de controle raiz.

    Imprimindo o conteúdo do arquivo /sys/fs/cgroup/cgroup.controllers na tela:

    sudo cat /sys/fs/cgroup/cgroup.controllers
    cpuset cpu io memory hugetlb pids rdma misc

    Você pode adicionar qualquer controlador listado no arquivo cgroup.controllers ao arquivo cgroup.subtree_control no mesmo diretório para disponibilizá-los para o filho imediato do grupo cgroups.

  2. Adicione o controlador cpu ao arquivo cgroup.subtree_control para disponibilizá-lo para o filho imediato cgroups da raiz.

    Por padrão, somente os controladores memory e pids estão no arquivo. Para adicionar o controlador cpu, digite:

    echo "+cpu" | sudo tee /sys/fs/cgroup/cgroup.subtree_control
    
  3. Opcionalmente, verifique se o controlador cpu foi adicionado conforme esperado.
    sudo cat /sys/fs/cgroup/cgroup.subtree_control
    cpu memory pids
  4. Crie um grupo filho no grupo de controle raiz para se tornar o novo grupo de controle para gerenciar recursos da CPU em aplicativos.
    sudo mkdir /sys/fs/cgroup/MyGroups
  5. Opcionalmente, liste o conteúdo do novo subdiretório ou grupo-filho e confirme se o controlador cpu está presente conforme esperado.
    ls -l /sys/fs/cgroup/MyGroups
    -r—​r—​r--. 1 root root 0 Jun  1 10:33 cgroup.controllers
    -r—​r—​r--. 1 root root 0 Jun  1 10:33 cgroup.events
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 cgroup.freeze
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 cgroup.max.depth
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 cgroup.max.descendants
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 cgroup.procs
    -r—​r—​r--. 1 root root 0 Jun  1 10:33 cgroup.stat
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 cgroup.subtree_control
    …​
    -r—​r—​r--. 1 root root 0 Jun  1 10:33 cpu.stat
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 cpu.weight
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 cpu.weight.nice
    …​
    -r—​r—​r--. 1 root root 0 Jun  1 10:33 memory.events.local
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 memory.high
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 memory.low
    …​
    -r—​r—​r--. 1 root root 0 Jun  1 10:33 pids.current
    -r—​r—​r--. 1 root root 0 Jun  1 10:33 pids.events
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 pids.max
  6. Ative o controlador cpu no arquivo cgroup.subtree_control no diretório MyGroups para disponibilizá-lo ao seu filho imediato cgroups.
    echo "+cpu" | sudo tee /sys/fs/cgroup/MyGroups/cgroup.subtree_control
  7. Opcionalmente, verifique se o controlador cpu está ativado para grupos filhos em MyGroups.
    sudo cat /sys/fs/cgroup/MyGroups/cgroup.subtree_control
    cpu

Definindo Peso da CPU para Regulamentar a Distribuição do Tempo da CPU

Este procedimento descreve como definir o peso da CPU para três processos diferentes usando um grupo de controle para gerenciar a distribuição do tempo da CPU. Observe que a abordagem recomendada para configurar grupos de controle é usar o systemd.

Este procedimento baseia-se nos seguintes pressupostos:

  • O aplicativo que está consumindo recursos da CPU excessivamente é sha1sum, conforme mostrado na seguinte saída de amostra do comando top:

    sudo top
    ...
    PID   USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
    33301 root      20   0   18720   1756   1468 R  99.0   0.0   0:31.09 sha1sum
    33302 root      20   0   18720   1772   1480 R  99.0   0.0   0:30.54 sha1sum
    33303 root      20   0   18720   1772   1480 R  99.0   0.0   0:30.54 sha1sum
    1 root      20   0  109724  17196  11032 S   0.0   0.1   0:03.28 systemd                     
    2 root      20   0       0      0      0 S   0.0   0.0   0:00.00 kthreadd                    
    3 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 rcu_gp                      
    4 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 rcu_par_gp                  
              ...
  • Os processos do sha1sum têm PIDs 33301, 33302 e 33303, conforme listado na saída de amostra anterior.

Importante

Como pré-requisito para o procedimento a seguir, você deve concluir as preparações do cgroup-v2, conforme descrito em Preparando o Grupo de Controle para Distribuição de Tempo de CPU. Se você ignorou essas preparações, não poderá concluir este procedimento.

  1. Crie 3 grupos filhos no subdiretório MyGroups.
    sudo mkdir /sys/fs/cgroup/MyGroups/g1
    sudo mkdir /sys/fs/cgroup/MyGroups/g2
    sudo mkdir /sys/fs/cgroup/MyGroups/g3
  2. Configure o peso da CPU para cada grupo filho.
    echo "150" | sudo tee /sys/fs/cgroup/MyGroups/g1/cpu.weight
    echo "100" | sudo tee /sys/fs/cgroup/MyGroups/g2/cpu.weight
    echo "50" | sudo tee /sys/fs/cgroup/MyGroups/g3/cpu.weight
  3. Aplique os PIDs do aplicativo aos grupos filhos correspondentes.
    echo "33301" | sudo tee /sys/fs/cgroup/MyGroups/g1/cgroup.procs
    echo "33302" | sudo tee /sys/fs/cgroup/MyGroups/g2/cgroup.procs
    echo "33303" | sudo /sys/fs/cgroup/MyGroups/g3/cgroup.procs

    Esses comandos definem os aplicativos selecionados para se tornarem membros dos grupos de controle MyGroups/g*/. O tempo de CPU para cada processo sha1sum depende da distribuição de tempo de CPU conforme configurado para cada grupo.

    Os pesos dos grupos g1, g2 e g3 que têm processos em execução são somados no nível MyGroups, que é o grupo de controle pai.

    Com essa configuração, quando todos os processos são executados ao mesmo tempo, o kernel aloca a cada um dos sha1sum processa o tempo de CPU proporcional com base no respectivo arquivo cpu.weight do cgroup, da seguinte forma:

    Grupo secundário Definição cpu.weight Porcentagem de alocação de tempo de CPU
    g1 150 ~50% (150/300)
    g2 100 ~33% (100/300)
    g3 50 ~16% (50/300)

    Se um grupo filho não tiver processos em execução, a alocação de tempo de CPU para processos em execução será recalculada com base no peso total dos grupos filhos restantes com processos em execução. Por exemplo, se o grupo filho g2 não tiver nenhum processo em execução, o peso total se tornará 200, que é o peso de g1+g3. Neste caso, o tempo de CPU para g1 torna-se 150/200 (~75%) e para g3, 50/200 (~25%)

  4. Verifique se os aplicativos estão em execução nos grupos de controle especificados.
    sudo cat /proc/33301/cgroup /proc/33302/cgroup /proc/33303/cgroup
    0::/MyGroups/g1
    0::/MyGroups/g2
    0::/MyGroups/g3
  5. Verifique o consumo atual da CPU depois de definir os pesos da CPU.
    top
    ...
    PID   USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
    33301 root      20   0   18720   1748   1460 R  49.5   0.0 415:05.87 sha1sum
    33302 root      20   0   18720   1756   1464 R  32.9   0.0 412:58.33 sha1sum
    33303 root      20   0   18720   1860   1568 R  16.3   0.0 411:03.12 sha1sum
    760 root      20   0  416620  28540  15296 S   0.3   0.7   0:10.23 tuned
    1 root      20   0  186328  14108   9484 S   0.0   0.4   0:02.00 systemd
    2 root      20   0       0      0      0 S   0.0   0.0   0:00.01 kthread
    ...