limites de recursos do cgroups v2 com systemd

11 min de leitura - 3 de junho de 2026

hero section cover
Índice
  • Limites de recursos do cgroups v2 com o systemd
  • Ativar cgroups v2
  • Como o systemd organiza os cgroups
  • Limites da CPU
  • Limites de memória com cgroups v2
  • Limites de E/S
  • Isolamento multitenant com fatias
  • Monitorização com o systemd-cgtop e o PSI
Partilhar

Definir limites de CPU, memória e E/S com cgroups v2 e systemd. Configuração prática para hosts Linux multi-tenant, com monitorização PSI e isolamento de slice.

Limites de recursos do cgroups v2 com o systemd

O cgroups v2 é a estrutura unificada de controlo de recursos do kernel Linux. Substitui a hierarquia fragmentada da v1 por uma única árvore que gere a CPU, a memória e as E/S de forma consistente, e sustenta o isolamento de contentores no Docker, Kubernetes e systemd. Esta publicação aborda como ativar o cgroups v2, definir limites através do systemd e aplicá-lo a cenários reais de alojamento multi-tenant.

Ativar cgroups v2

As distribuições modernas vêm com os cgroups v2 ativados por predefinição: Ubuntu 21.10+, Debian 11+, Fedora 31+ e RHEL/Rocky 9+. Os sistemas mais antigos podem executar uma hierarquia híbrida ou ainda ter a v1 como predefinição. Verifique com:

stat -fc %T /sys/fs/cgroup/

A saída de cgroup2fs confirma que a v2 está ativa. tmpfs normalmente significa v1.

Para mudar um sistema híbrido para v2 puro, edite /etc/default/grub e acrescente o seguinte a GRUB_CMDLINE_LINUX_DEFAULT:

systemd.unified_cgroup_hierarchy=1 cgroup_no_v1=all

Em seguida, gere novamente o GRUB e reinicie:

sudo update-grub
sudo reboot

Para produção, execute o kernel 5.2 ou mais recente para obter o cgroup freezer para a v2 e o systemd 244+ para a cpuset . No Rocky Linux 8 e no RHEL 8, poderá também ser necessário ativar a contabilidade explicitamente, adicionando estas linhas a /etc/systemd/system.conf:

DefaultCPUAccounting=yes
DefaultMemoryAccounting=yes
DefaultIOAccounting=yes

Recarregue com sudo systemctl daemon-reexec. Após o reinício, verifique quais controladores estão disponíveis:

cat /sys/fs/cgroup/cgroup.controllers

Deve ver cpu, memory, ioe pids listados. Estes controladores não estão ativados para cgroups filhos por predefinição. Para os ativar, escreva no ficheiro de controlo da subárvore raiz:

echo "+cpu +memory +io" | sudo tee /sys/fs/cgroup/cgroup.subtree_control

Para uma visão completa de como a v2 difere da v1 internamente, a palestra de Michael Kerrisk na NDC TechTown é o melhor recurso disponível:

Como o systemd organiza os cgroups

O systemd cria um cgroup para cada serviço que inicia, com o nome da unidade. nginx.service obtém /sys/fs/cgroup/system.slice/nginx.service/, e todos os processos que gera residem dentro desse cgroup. Três tipos de unidade correspondem diretamente à hierarquia:

Tipo de unidadeFunçãoDescrição
.sliceNó internoAgrupa serviços relacionados e define limites partilhados
.serviceNó terminalGere processos iniciados pelo systemd
.scopeNó folhaAcompanha processos iniciados externamente (cargas úteis de contentores, sessões de início de sessão)

Quatro fatias padrão são fornecidas de fábrica: -.slice (raiz), system.slice, user.slicee machine.slice. Qualquer limite aplicado a uma fatia aplica-se automaticamente a todos os serviços nela contidos.

Uma regra da v2 que vale a pena lembrar: os processos só podem residir em nós folha. Um cgroup com cgroups filhos não pode hospedar processos diretamente, razão pela qual o systemd nunca coloca serviços no tronco de uma fatia.

Defina sempre os limites através do systemd em vez de escrever /sys/fs/cgroup/ diretamente. As gravações manuais não persistem após reinicializações e entram em conflito com a propriedade exclusiva da hierarquia pelo systemd. Use systemctl set-property para alterações pontuais e unit drop-ins (systemctl edit nginx.service) para alterações permanentes.

Limites da CPU

O cgroups v2 oferece dois controlos de CPU: um limite rígido (cpu.max, exposto como CPUQuota no systemd) e um peso proporcional (cpu.weight / CPUWeight).

CPUQuota é um limite máximo absoluto. CPUQuota=50% permite meio núcleo; CPUQuota=200% permite o tempo equivalente a dois núcleos completos. O serviço é limitado se tentar ultrapassar esse valor, independentemente do nível de inatividade do resto da CPU.

CPUWeight só importa em caso de contenção. O intervalo é de 1 a 10 000, sendo o valor padrão 100. Três serviços com pesos de 150, 100 e 50 recebem aproximadamente 50%, 33% e 17% do tempo de CPU quando todos o pretendem ao mesmo tempo. Quando a CPU está ociosa, os pesos não restringem nada.

Para cargas de trabalho sensíveis à latência, fixe os processos a núcleos específicos com AllowedCPUs=. Isto reduz a troca de contexto e mantém a cache por núcleo ativa:

[Service]
CPUQuota=200%
CPUWeight=150
AllowedCPUs=0-3

Utilize uma quota rígida quando precisar de custos previsíveis (faturação multi-tenant, isolamento de vizinhos ruidosos). Utilize pesos quando pretender a máxima utilização do hardware e apenas precisar de uma ordem de prioridade durante picos de carga.

Limites de memória com cgroups v2

A memória tem dois níveis: memory.high (suave, limitação) e memory.max (rígido, OOM). Para obter informações sobre swap, recuperação de páginas e o OOM killer do kernel, consulte a nossa publicação complementar sobre gestão de memória no Linux.

Defina memory.high aproximadamente 10 a 20% abaixo memory.max. O kernel começa a recuperar páginas e a limitar as alocações assim que memory.high é ultrapassado, o que normalmente permite que a carga de trabalho se recupere antes de o OOM killer ser acionado. Se a utilização atingir memory.max, o kernel encerra processos no cgroup.

Uma configuração típica:

[Service]
MemoryHigh=400M
MemoryMax=512M
MemorySwapMax=0

MemorySwapMax=0 desativa o swap para este cgroup. Vale a pena fazer isso para cargas de trabalho sensíveis à latência (bases de dados, streaming em tempo real), onde a E/S do swap prejudicaria a latência de cauda.

Para conjuntos de trabalhadores em que deixar irmãos órfãos para trás corromperia o estado partilhado, escreva 1 no ficheiro memory.oom.group . Quando um processo é encerrado por OOM, o kernel encerra todos os processos no cgroup em conjunto.

Verifique memory.events para ver com que frequência um serviço foi limitado ou encerrado por OOM:

cat /sys/fs/cgroup/system.slice/nginx.service/memory.events

O high e oom_kill indicam se os seus limites estão dimensionados corretamente. Valores persistentes diferentes de zero significam que a carga de trabalho precisa de mais margem.

Limites de E/S

O controlador de E/S tem o mesmo design de dois modos: limites absolutos através io.max e partilha proporcional via io.weight.

Os limites são por dispositivo de bloco, identificados por números major:minor. Encontre-os com lsblk -o NAME,MAJ:MIN. Uma configuração típica do systemd:

[Service]
IOReadBandwidthMax=/dev/sda 50M
IOWriteBandwidthMax=/dev/sda 30M
IOReadIOPSMax=/dev/sda 1000
IOWriteIOPSMax=/dev/sda 500

io.weight funciona como cpu.weight: intervalo de 1 a 10 000, valor padrão 100. Atribuir 500 a um serviço voltado para o cliente e 50 a um backup noturno evita que o backup sature o disco durante os horários de pico, mas permite que ele use toda a largura de banda quando nada mais a necessita.

Os limites de E/S só se aplicam quando se direciona o dispositivo certo. O kernel rastreia a E/S por dispositivo de bloco, portanto, um limite em /dev/sda não tem efeito sobre a E/S que vai para /dev/nvme0n1. Em hosts com vários discos, defina limites por dispositivo.

Isolamento multitenant com fatias

Para ambientes partilhados, defina uma fatia por inquilino. Crie /etc/systemd/system/tenant-a.slice:

[Slice]
CPUQuota=200%
CPUWeight=150
MemoryHigh=3584M
MemoryMax=4096M
MemorySwapMax=0
IOReadBandwidthMax=/dev/sda 200M
TasksMax=512

TasksMax=512 limita o número total de processos e threads, o que impede que uma bomba de fork num inquilino derrube o anfitrião. Coloque os serviços do inquilino nesta fatia (através Slice=tenant-a.slice nos seus ficheiros de unidade) e estes herdam tudo automaticamente.

Este padrão também funciona para separar tarefas de fundo ruidosas dos serviços voltados para o utilizador. Coloque backups, rotação de logs e tarefas em lote numa background.slice com baixo CPUWeight e io.weight . Recebem recursos completos quando o sistema está inativo e dão lugar quando o tráfego de produção chega.

Para ambientes de execução de contentores como o Docker e o Podman, adicione Delegate=yes aos seus ficheiros de unidade do systemd. Isto permite-lhes gerir os seus próprios sub-cgroups sem direitos de root, e os limites definidos na fatia pai continuam a aplicar-se a tudo o que está abaixo.

Monitorização com o systemd-cgtop e o PSI

Para uma visualização em tempo real, ao estilo do top, da CPU, da memória e da E/S por cgroup, execute:

systemd-cgtop

Para a hierarquia estática e para saber quais os processos que se encontram em cada local, utilize systemd-cgls.

A funcionalidade v2 mais útil para monitorização em produção é a Pressure Stall Information (PSI). A PSI reporta a percentagem de tempo em que as tarefas num cgroup ficaram paralisadas à espera de um recurso, apresentada em três ficheiros por cgroup:

cat /sys/fs/cgroup/tenant-a.slice/cpu.pressure
cat /sys/fs/cgroup/tenant-a.slice/memory.pressure
cat /sys/fs/cgroup/tenant-a.slice/io.pressure

Uma CPU com 100% de utilização e 0% de pressão está em bom estado. Todas as tarefas que necessitam de CPU estão a obtê-la. A mesma CPU com 80% de utilização, mas 30% de pressão, significa que as tarefas estão em fila para tempo de execução. Alerte com base no PSI, não na utilização: este deteta conflitos que as métricas de utilização ignoram completamente.

Ajuste os limites em tempo real sem reiniciar nada:

sudo systemctl set-property tenant-a.slice MemoryMax=6144M

A alteração aplica-se imediatamente e persiste após reinicializações. Combinado com alertas baseados no PSI, isto permite-lhe responder a mudanças de carga antes que se transformem em encerramentos por OOM ou latência descontrolada.

Se estiver a executar cargas de trabalho multitenant de alta densidade e precisar de um host com capacidade para aplicar estas políticas de forma eficaz, os nossos servidores dedicados foram concebidos para isso.

Blogue

Em destaque esta semana

Mais artigos
Porque é que é importante ter um VPS potente e ilimitado

Porque é que é importante ter um VPS potente e ilimitado

Um VPS não medido fornece largura de banda fixa a uma velocidade de porta fixa. Como difere dos planos com contador, quando compensa e o que verificar antes de comprar.

7 min de leitura - 9 de maio de 2025

Gestão de memória do Linux: Swap, OOM Killer & Cgroups

12 min de leitura - 31 de maio de 2026

Mais artigos