A luta por recursos, parte 6: cpuset ou compartilhamento nem sempre está certa

Ao falar sobre cgroups, os usuários do Red Hat costumam fazer a mesma pergunta: “Eu tenho um aplicativo que é muito sensível em termos de atrasos. É possível usar cgroups para isolar esse aplicativo do restante, vinculando-o a determinados núcleos do processador? ”



Claro que você pode. Caso contrário, não escolheríamos esse problema como o tópico do artigo de hoje.

Na infância, muitas vezes nos disseram que compartilhar é bom e correto. Em geral, do jeito que está. Mas há exceções.

Como escrevemos no primeiro post desta série , por padrão, o Red Hat Enterprise Linux 7 se comporta como uma avó esférica. No sentido de que ela está tentando distribuir de maneira justa os recursos do sistema entre todos os que os solicitarem. No entanto, na vida real, as avós têm animais de estimação que recebem mais. Traduzido para o sysadmin, isso significa que existem situações em que alguns aplicativos ou serviços são mais importantes que outros; portanto, eles devem receber toda a atenção possível para que sejam o mais responsivos possível.

O Red Hat Enterprise Linux 7 faz isso em duas etapas:

  1. Isolamos parte dos núcleos do processador para transferi-los para o uso exclusivo desse aplicativo.
  2. Criamos grupos cgroups e arquivos de unidades que vinculam esse aplicativo a kernels isolados.

Uma pequena digressão sobre os exemplos desses posts


O Hat Enterprise Linux 7.4 mudou o funcionamento das fatias de curta duração, como sessões de usuário. Como resultado, eles não podem mais alterar as configurações do cgroup em tempo real, fazer alterações permanentes na configuração ou criar arquivos drop-in usando o comando systemctl set-property. Sim, é uma pena, mas a comunidade de desenvolvimento Linux decidiu que sim. A boa notícia é que essas mudanças não afetaram o serviço. Ou seja, se os aplicativos iniciam e param nos arquivos da unidade (funcionam como daemons), todos os nossos exemplos funcionam. Além disso, ainda é possível criar seus próprios cgroups usando ferramentas antigas, como cgcreate e cgset, e depois colocar sessões e processos de usuário nesses grupos para usar esferas da CPU e outros controles. Na vida, tudo muda, então só podemos adaptar e inventar novas técnicas. E agora nos voltamos para o tópico de hoje.

Construindo separatismo com isolcpus


Um dos componentes mais importantes no kernel do Linux é o agendador de processos. Se um pouco mais profundo, então um processo é um código executável que faz parte de um aplicativo ou serviço. De fato, o processo consiste em uma série de instruções que o computador executa, realizando este ou aquele trabalho, seja olhando selos ou algo mais sério.

Essas instruções são tratadas pelo processador central, também conhecido como CPU. Em computadores modernos, a CPU geralmente consiste em vários processadores chamados núcleos.

Por padrão, o planejador considera cada núcleo do processador como um dos módulos executivos aos quais atribui novos processos à medida que aparecem. Nesse caso, o planejador tenta distribuir de maneira mais ou menos uniforme os processos emergentes entre os núcleos, levando em consideração a carga. Infelizmente, o planejador não pode ser informado de que esse processo específico acabará gerando um grupo inteiro de processos, e esse grupo precisará ser executado isoladamente de outros processos, no sentido de que eles não devem ter núcleos de processador comuns.

Portanto, precisamos dizer de alguma forma ao planejador para que ele não toque em parte dos núcleos do processador, ou seja, não lhes dê nenhum processo que acerte. E então nós mesmos (ou com a ajuda de algum outro processo) forçaremos os processos que consideramos necessários para serem isolados do agendador do kernel. Isso pode ser feito usando o parâmetro isolcpus na linha de inicialização do kernel no arquivo de configuração do grub. No exemplo abaixo, temos uma máquina com quatro kernels nos quais existem dois arquivos grub: um está no / etc / default e é chamado grub.noiso (este é o backup de configuração padrão), e o segundo está lá e é simplesmente chamado grub para que ele pegou grub2-mkconfig. Este segundo arquivo foi editado para isolar os kernels 1-3 do agendador de processos.


AVISO: no Red Hat Enterprise Linux 7, você nunca precisa modificar manualmente o arquivo grub.conf na pasta / boot. Em vez disso, faça as alterações necessárias em / etc / default / grub e recrie o arquivo grub.conf usando o utilitário apropriado, por exemplo, como este:


Ao usar o parâmetro isolcpus, é necessário listar os núcleos do processador liberados separados por vírgulas, a numeração começa em 0. Após o sistema reiniciar, o agendador de processos não utilizará esses núcleos para nada, exceto para determinados processos no nível do sistema que DEVEM ESTAR em cada núcleo. Para verificar se nosso método funcionou, iniciaremos vários processos de carregamento e, em seguida, examinaremos o carregamento de cada kernel por meio do comando top.


Como você pode ver, todos os processos de carregamento estavam na CPU 0, em vez de serem distribuídos igualmente nos quatro núcleos. Então, registramos o parâmetro de inicialização corretamente.

Vincular processos a kernels usando cpuset


Agora passamos a coisas que é melhor não fazer se você não entender por que está fazendo isso e quais são melhores para implantar na produção somente após testes completos .

Para que servem esses avisos? Ao fato de que, em geral, faremos coisas simples usando o libcgroup toolkit, que foi escrito em uma postagem anterior. Se você se lembra, este é apenas um conjunto de comandos para criar, modificar e destruir cgroups. De fato, eles fazem parte do Red Hat Enterprise Linux 6, mas também podem ser instalados no Red Hat Enterprise Linux 7, embora seja possível que essa possibilidade desapareça no futuro. Lembre-se brevemente das principais recomendações para o uso do libcgroup:

  1. Use systemd para controlar os controladores cgroup que estão sob o controle do próprio systemd (estes são CPU, memória e E / S de bloco).
  2. Use as ferramentas libcgroup para gerenciar todos os outros controladores cgroup.
  3. Tenha muito cuidado com as consequências não planejadas de suas ações.

Tudo é simples com o conceito cpuset - esta é uma lista de núcleos de processador (numeração, recall, inicia em 0), que aceita tarefas que serão executadas SOMENTE nesses núcleos. Esses são os núcleos mais comuns do processador, podem ser controlados por um agendador de processos (é assim que o sistema é configurado por padrão) ou, por outro lado, podem ser isolados do agendador (como fizemos no exemplo acima).

Vamos verificar o diretório / sys / fs / cgroup filesystem no sistema a partir do nosso exemplo. Como você pode ver, o diretório cpuset já existe, pois esse controlador faz parte do kernel (embora não esteja sob o controle do systemd). No entanto, ele ainda não possui cgroups, portanto, vemos apenas as configurações padrão neste diretório.


Verifique se o libcgroup toolkit está instalado em nossa máquina:


Se não estiver instalado, isso poderá ser facilmente corrigido com o comando yum install libcgroup, nem mesmo uma reinicialização.

Agora crie cpuset. Para fazer isso, usaremos os seguintes comandos para criar um novo cgroup para cpuset e registrar suas propriedades:


O comando Cgcreate cria um cgroup chamado testset e o coloca dentro do controlador cpuset. Em seguida, atribuímos o terceiro núcleo da nossa VM a esse novo cpuset e alocamos a zona NUMA 0. Mesmo que seu sistema não use o NUMA (e o nosso simplesmente não o usa), você ainda precisará registrar a zona, caso contrário, não poderá atribuir tarefas ao grupo cgroup . Agora verifique se o diretório testset foi criado no sistema de arquivos e veja o que está dentro dele.


Como você pode ver, nossas alterações estão em vigor, mas até agora nenhum processo foi executado neste cpuset. Como plantar algum processo aqui?

Existem várias maneiras de fazer isso:

  • Você pode direcionar o PID de um processo existente para o arquivo de tarefas. Funciona, mas não é muito bonito.
  • Você pode usar o cgexec e especificar o grupo quando o processo iniciar. Isso funciona se o aplicativo não for um daemon; Além disso, tudo isso pode ser muito bem escrito no script de inicialização do aplicativo.
  • Para um aplicativo que é executado como um daemon executando systemd, você pode criar um arquivo de serviço.

Vamos ver a opção cgexec.


Lançamos o foo.exe, por sua vez, lançou um processo filho, o que apenas faz isso carregar ativamente o processador. A opção --sticky no comando cgexec diz que "qualquer processo filho deve permanecer no mesmo cgroup que o processo pai". Portanto, essa é uma opção importante e deve ser lembrada. Agora vemos que dois processos estão girando em nosso cgroup e conhecemos seus PIDs. Dê uma olhada no topo:


Como você pode ver, a CPU 3 agora está carregada nos globos oculares e o restante está esfriando.

E aqui está a aparência de um arquivo de unidade para executar o mesmo aplicativo que um serviço systemd:


Existem três comandos ExecStartPre no arquivo da unidade que executam as configurações que já conseguimos fazer com nossas mãos. Em seguida, vem o comando ExecStart, que inicia o aplicativo. E quando o aplicativo é interrompido, o comando ExecStopPost é limpo automaticamente, removendo o cgroup.


Como você pode ver, no último exemplo, criamos um novo cgroup chamado set1. Fizemos isso para mostrar que você pode ter vários cgroups ativos que compartilham a mesma CPU. Para quem pode parecer útil, mas, pelo contrário, confundir alguém.

Bem, isso funciona? Parece que sim!


E agora concluiremos o trabalho do nosso serviço e verificaremos se o cgroup está destruído:


ATENÇÃO: os grupos cgroup criados usando cgcreate não são salvos após a reinicialização. Portanto, a criação desses grupos deve ser prescrita nos scripts de inicialização e nos arquivos da unidade.

Então agora em seu arsenal existem mais algumas ferramentas para trabalhar com cgroups. Esperamos que eles sejam úteis!

Outras postagens de cgroups de nossa série Resource Fight estão disponíveis em:

Source: https://habr.com/ru/post/pt430748/


All Articles