Ajustar o desempenho do nó

Uma maneira de melhorar o desempenho de aplicativos com base em contêineres é aumentar os recursos do cluster adicionando nós ou adicionando recursos, como CPUs ou memória, a eles. Essa abordagem, no entanto, pode se tornar cara. Ajustar os nós do cluster para melhorar o desempenho ajuda a otimizar a utilização de recursos das cargas de trabalho de maneira econômica. Neste documento, descrevemos como usar o Operador de ajuste de desempenho para ajustar nós de trabalho e otimizar o desempenho da carga de trabalho do GKE em Bare Metal.

Para aproveitar ao máximo o hardware e o software subjacentes, diferentes tipos de aplicativos, especialmente aplicativos de alto desempenho, se beneficiam do ajuste das configurações de nós, como o seguinte:

  • CPUs dedicadas para cargas de trabalho sensíveis ao desempenho
  • CPUs reservadas para daemons e serviços padrão do Kubernetes
  • Aumento do tamanho das páginas de memória com páginas enormes de 1 GiB (gibibyte) ou 2 MiB (mebibyte)
  • Distribuição de cargas de trabalho com base na arquitetura do sistema, como processadores de vários núcleos e NUMA

Com o operador de ajuste de desempenho, é possível definir configurações de desempenho no nível do nó criando recursos personalizados do Kubernetes que aplicam configurações de desempenho. Confira os benefícios:

  • Interface de configuração única e unificada: com o operador de ajuste de desempenho, é possível atualizar um ou mais manifestos PerformanceTuningProfile que podem ser aplicados a nós de trabalho com seletores de nós. Não é preciso configurar cada nó individualmente com várias configurações e definições de políticas. Essa abordagem permite gerenciar configurações no nível do nó e do contêiner de maneira única e unificada.

  • Persistência e confiabilidade: com a arquitetura de alta disponibilidade, você também aproveita toda a confiabilidade do Kubernetes. Os recursos personalizados do PerformanceTuningProfile podem ser atualizados sempre que você quiser, e as configurações deles persistem nas principais operações de cluster, como upgrades.

O operador de ajuste de desempenho orquestra os seguintes recursos e ferramentas do Kubernetes e do sistema operacional (SO) relacionados ao desempenho:

Para evitar conflitos, ao usar o operador de ajuste de desempenho, recomendamos que você não use as ferramentas e os recursos do Kubernetes e do SO mencionados anteriormente de maneira independente.

Pré-requisitos e limitações

Veja os pré-requisitos e as limitações para usar o operador de ajuste de desempenho:

  • Somente Red Hat Enterprise Linux (RHEL): o operador de ajuste de desempenho é compatível apenas com nós que executam versões compatíveis do RHEL.

  • Cluster de usuário ou híbrido com nós de trabalho: o operador de ajuste de desempenho pode ser usado apenas com nós de trabalho em clusters híbridos ou de usuários. Não é possível usar o operador de ajuste de desempenho para ajustar os nós do plano de controle. O operador de ajuste de desempenho usa um seletor de nós para determinar como aplicar os perfis de ajuste. Para garantir que os perfis de ajuste sejam aplicados apenas aos nós de trabalho, o nodeSelector em cada recurso personalizado de perfil precisa incluir o rótulo de nó de trabalho padrão node-role.kubernetes.io/worker: "". Se o nodeSelector em um perfil de ajuste corresponder a rótulos em um nó do plano de controle, esse nó não será ajustado e uma condição de erro será definida. Para mais informações sobre condições de erro, consulte Verificar status. Verifique se o cluster está funcionando corretamente antes de instalar o operador de ajuste de desempenho e aplicar perfis de ajuste.

  • TuneD 2.22.0: o operador de ajuste de desempenho exige que a versão 2.22.0 do TuneD seja pré-instalada nos nós de trabalho que você pretende ajustar. Para mais informações sobre o TuneD, incluindo instruções de instalação, consulte Introdução ao TuneD na documentação do Red Hat Enterprise Linux. O operador de ajuste de desempenho usa o TuneD com o perfil cpu-partitioning. Se não tiver esse perfil, instale-o com o seguinte comando:

    dnf install -y tuned-profiles-cpu-partitioning
    
  • Requisitos de recursos de carga de trabalho: para aproveitar ao máximo o ajuste de desempenho, é preciso ter uma boa compreensão dos requisitos de memória e CPU (solicitações e limites de recursos) para suas cargas de trabalho.

  • Recursos de nó disponíveis: encontre os recursos de CPU e memória para seus nós. É possível receber informações detalhadas sobre CPU e memória do nó nos arquivos /proc/cpuinfo e /proc/meminfo, respectivamente. Também é possível usar kubectl get nodes para recuperar a quantidade de recursos de computação e memória (status.allocatable) que um nó de trabalho tem disponíveis para pods.

  • Requer diminuição: como parte do processo de ajuste, o operador de ajuste de desempenho primeiro drena os nós e depois aplica um perfil de ajuste. Como resultado, os nós podem informar um status NotReady durante o ajuste de desempenho. Recomendamos que você use a estratégia de atualização gradual (spec.updateStrategy.type: rolling) em vez de uma atualização em lote para minimizar a indisponibilidade da carga de trabalho.

  • Requer reinicialização: para que as alterações de ajuste de nós entrem em vigor, o operador de ajuste de desempenho reinicializa o nó depois de aplicar o perfil de ajuste.

Instalar o operador de ajuste de desempenho

O operador de ajuste de desempenho consiste principalmente em dois controladores (uma implantação e um DaemonSet) que interagem entre si para ajustar os nós com base nas configurações do perfil. O Operador de ajuste de desempenho não é instalado com o GKE em Bare Metal por padrão. Faça o download dos manifestos do operador de ajuste de desempenho do Cloud Storage e use kubectl apply para criar recursos do operador de ajuste de desempenho no cluster.

Para ativar o ajuste de desempenho com valores padrão para o cluster:

  1. Crie um diretório performance-tuning na estação de trabalho do administrador.

  2. No diretório performance-tuning, faça o download do pacote mais recente do operador de ajuste de desempenho no bucket de lançamento do Cloud Storage:

    gsutil cp -r gs://anthos-baremetal-release/node-performance-tuning/0.1.0-gke.47 .
    

    Os arquivos transferidos por download incluem manifestos para a implantação performance-tuning-operator e o DaemonSet nodeconfig-controller-manager. Também estão incluídos manifestos para funções relacionadas, como controle de acesso baseado em função (RBAC) e controle de admissão dinâmica.

  3. Como usuário raiz, aplique todos os manifestos do Operador de ajuste de desempenho de maneira recursiva ao cluster de usuário (ou híbrido):

    kubectl apply -f performance-tuning --recursive –-kubeconfig USER_KUBECONFIG
    

    Depois que a implantação e o DaemonSet são criados e executados, sua única interação é editar e aplicar os manifestos PerformanceTuningProfile.

Confira os requisitos de recursos para suas cargas de trabalho

Antes de ajustar seus nós, você precisa entender os requisitos de recursos de computação e memória das suas cargas de trabalho. Se os nós de trabalho tiverem recursos suficientes, eles poderão ser ajustados para fornecer memória garantida (padrão e grandes páginas) às cargas de trabalho na classe garantida Qualidade de Serviço (QoS).

O Kubernetes atribui classes de QoS a cada um dos pods, com base nas restrições de recursos especificadas para os contêineres associados. Em seguida, o Kubernetes usa classes QoS para determinar como programar pods e contêineres e alocar recursos para suas cargas de trabalho. Para aproveitar ao máximo o ajuste de nós para suas cargas de trabalho, elas precisam ter solicitações de recursos de CPU ou memória ou configurações de limites.

Para receber uma classe de QoS garantida, seus pods precisam atender aos seguintes requisitos:

  • Para cada contêiner no pod:
    • Especifique valores para solicitações de recursos de memória (spec.containers[].resources.requests.memory) e limites (spec.containers[].resources.limits.memory).
    • O valor dos limites de memória precisa ser igual ao valor das solicitações de memória.
    • Especifique valores para solicitações de recurso de CPU (spec.containers[].resources.requests.cpu) e limites (spec.containers[].resources.limits.cpu).
    • O valor dos limites da CPU precisa ser igual ao valor de solicitações da CPU.

O trecho de especificação de pod a seguir mostra as configurações de recursos da CPU que atendem aos requisitos garantidos da classe QoS:

spec:
  containers:
  - name: sample-app
    image: images.my-company.example/app:v4
    resources:
      requests:
        memory: "128Mi"
        cpu: "2"
      limits:
        memory: "128Mi"
        cpu: "2"
  ...

Quando você recupera detalhes do pod com kubectl get pods, a seção status precisa incluir a classe de QoS atribuída, conforme mostrado no exemplo a seguir:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2023-09-22T21:05:23Z"
  generateName: my-deployment-6fdd69987d-
  labels:
    app: metrics
    department: sales
    pod-template-hash: 6fdd69987d
  name: my-deployment-6fdd69987d-7kv42
  namespace: default
  ...
spec:
  containers:
  ...
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: "2023-09-22T21:05:23Z"
    status: "True"
    type: Initialized
  ...
  qosClass: BestEffort
  startTime: "2023-09-22T21:05:23Z"

Para mais informações sobre as classes de QoS, consulte Qualidade de pod de classes de serviço na documentação do Kubernetes. Para instruções sobre como configurar pods e contêineres para que recebam uma classe de QoS, consulte Configurar a qualidade de serviço para pods.

Requisitos de CPU

Ao ajustar um nó, é possível especificar um conjunto de núcleos de CPU reservados (spec.cpu.reservedCPUs) para executar daemons do sistema do Kubernetes, como o kubelet e o ambiente de execução do contêiner. Esse mesmo conjunto de CPUs reservadas executa daemons do sistema operacional, como sshd e udev, também. Os núcleos da CPU restantes são alocados como isolados. As CPUs isoladas são destinadas a aplicativos vinculados à CPU, que exigem tempo de CPU dedicado sem interferência de outros aplicativos ou interrupções de rede ou de outros dispositivos.

Para programar um pod nas CPUs isoladas de um nó de trabalho:

  • Configure o pod para ter uma Qualidade de Serviço (QoS) garantida.

  • Os requisitos e limites de CPU precisam ser especificados em números inteiros. Se você especificar recursos parciais de CPU na especificação do pod, como cpu: 0.5 ou cpu: 250m (250 milicores), a programação não poderá ser garantida.

Requisitos de memória

Ao ajustar um nó com o operador de ajuste de desempenho, é possível criar páginas enormes e associá-las aos nós de acesso à memória não uniforme (NUMA) na máquina. Com base nas configurações de pod e nó, os pods podem ser programados com afinidade de nó NUMA.

Criar um perfil de ajuste de desempenho

Depois de instalar o operador de ajuste de desempenho, você interage apenas com o cluster que executa suas cargas de trabalho. Recursos personalizados de PerformanceTuningProfile são criados diretamente no cluster de usuário ou no cluster híbrido, não no cluster de administrador. Cada recurso PerformanceTuningProfile contém um conjunto de parâmetros que especifica a configuração de desempenho aplicada a um nó.

O nodeSelector no recurso determina os nós em que o perfil de ajuste é aplicado. Para aplicar um perfil a um nó, coloque o rótulo do par de chave-valor correspondente no nó. Um perfil de ajuste é aplicado a nós que têm todos os rótulos especificados no campo nodeSelector.

É possível criar vários recursos PerformanceTuningProfile em um cluster. Se mais de um perfil corresponder a um determinado nó, uma condição de erro será definida no status do recurso personalizado PerformanceTuningProfile. Para mais informações sobre a seção status, consulte Verificar status.

Defina o namespace do recurso personalizado PerformanceTuningProfile como kube-system.

Para ajustar um ou mais nós de trabalho:

  1. Editar o manifesto PerformanceTuningProfile.

    Para saber mais sobre cada campo e um manifesto de amostra, consulte a referência do recurso PerformanceTuningProfile.

  2. (Opcional) Para os nós de trabalho aos quais você está aplicando um perfil, adicione rótulos para corresponder ao par de chave-valor spec.nodeSelector.

    Se nenhum par de chave-valor spec.nodeSelector for especificado no recurso personalizado PerformanceTuningProfile, o perfil será aplicado a todos os nós de trabalho.

  3. Aplique o manifesto ao cluster.

    kubectl apply -f PROFILE_MANIFEST --kubeconfig KUBECONFIG
    

    Substitua:

    • PROFILE_MANIFEST: o caminho do arquivo de manifesto para o recurso personalizado PerformanceTuningProfile.
    • KUBECONFIG: o caminho do arquivo kubeconfig do cluster.

Remover um perfil de ajuste

Para redefinir um nó para seu estado original não ajustado:

  1. Exclua o recurso personalizado PerformanceTuningProfile do cluster.

  2. Atualize ou remova os rótulos no nó para que ele não seja selecionado pelo perfil de ajuste novamente.

Se você tiver vários perfis de ajuste associados ao nó, repita as etapas anteriores, conforme necessário.

Pausar um perfil de ajuste

Se você precisar realizar manutenção no cluster, será possível pausar temporariamente o ajuste editando o recurso personalizado PerformanceTuningProfile. Recomendamos que você pause o ajuste antes de executar operações críticas de cluster, como um upgrade de cluster.

A aplicação de perfil malsucedida é outro caso em que você pode pausar o ajuste. Se o processo de ajuste não for bem-sucedido, o controlador pode continuar tentando ajustar o nó, o que pode resultar na reinicialização do nó repetidamente. Se você observar o status do nó alterna entre os estados "pronto" e "não pronto", pause o ajuste para se recuperar do estado corrompido.

Para pausar a sintonização:

  1. Edite o manifesto do recurso personalizado PerformanceTuningProfile para definir spec.paused como true.

  2. Use kubectl apply para atualizar o recurso.

Quando o ajuste de desempenho é pausado, o controlador do operador de ajuste de desempenho interrompe todas as operações. A pausa evita o risco de operações do controlador do Operador de ajuste de desempenho conflitarem com qualquer operação do controlador bare metal do GKE.

PerformanceTuningProfile referência do recurso

Nesta seção, descrevemos cada um dos campos no recurso personalizado PerformanceTuningProfile. Esse recurso é usado para criar um perfil de ajuste para um ou mais dos nós do cluster. Todos os campos no recurso são mutáveis após a criação do perfil. Os perfis precisam estar no namespace kube-system.

O manifesto de amostra de perfil numa a seguir para nós com oito núcleos de CPU especifica as seguintes alocações de recursos:

  • Quatro núcleos de CPU (0-3) são reservados para a sobrecarga do sistema do Kubernetes.

  • Quatro núcleos de CPU (4-7) são reservados apenas para cargas de trabalho.

  • A memória do nó é dividida em páginas de 2 MiB por padrão, em vez das páginas padrão de 4Ki.

  • 10 páginas de memória de 1 GiB são reservadas para uso pelo nó NUMA 0.

  • Cinco páginas de memória com tamanho de 2 MiB são reservadas para uso pelo nó NUMA 1.

  • O Topology Manager usa a política de melhor esforço para programar cargas de trabalho.

apiVersion: anthos.gke.io/v1alpha1
kind: PerformanceTuningProfile
metadata:
  name: numa
  namespace: kube-system
spec:
  cpu:
    isolatedCPUs: 4-7
    reservedCPUs: 0-3
  defaultHugepagesSize: 2M
  nodeSelector:
    app: database
    node-role.kubernetes.io/worker: ""
  pages:
  - count: 10
    numaNode: 0
    size: 1G
  - count: 5
    numaNode: 1
    size: 2M
  topologyManagerPolicy: best-effort

É possível recuperar a definição do recurso personalizado PerformanceTuningProfile relacionado do grupo anthos.gke.io no cluster. A definição do recurso personalizado é instalada depois que a anotação do recurso de visualização é adicionada ao recurso de cluster autogerenciado.

Configuração de CPU

Propriedade Descrição
cpu.reservedCPUs Obrigatório. Mutável. String. Esse campo define um conjunto de núcleos de CPU a serem reservados para daemons do sistema Kubernetes, como o kubelet, o ambiente de execução do contêiner e o detector de problemas do nó. Esses núcleos de CPU também são usados para daemons do sistema operacional (SO), como sshd e udev.

O campo cpu.reservedCPUs usa uma lista de números de CPU ou intervalos de números de CPU. Verifique se a lista de CPUs não se sobrepõe à lista especificada com cpu.isolatedCPUs. A união das CPUs listadas nesses dois campos precisa incluir todas as CPUs do nó.

cpu.isolatedCPUs Opcional. Mutável. String. O campo cpu.isolatedCPUs define um conjunto de CPUs usadas exclusivamente para aplicativos sensíveis ao desempenho. O gerenciador de CPU programa contêineres apenas nas CPUs não reservadas, de acordo com as classes de Qualidade de Serviço (QoS) do Kubernetes. Para garantir que as cargas de trabalho sejam executadas nas CPUs isoladas, configure os pods com a classe QoS garantida e atribua um recurso de CPU ao pod ou contêiner. Para garantir a programação de pods, é preciso especificar unidades de CPU com números inteiros, não recursos parciais de CPU (cpu: "0.5").

apiVersion: v1
kind: Pod
...
spec:
  containers:
  ...
    resources:
      limits:
        cpu: "1"
      requests:
        cpu: "1"
  ...

A maximização de CPUs isoladas para cargas de trabalho oferece o melhor benefício de desempenho. Esse campo usa uma lista de números de CPU ou intervalos de números de CPU. Verifique se a lista de CPUs não se sobrepõe à lista especificada com cpu.reservedCPUs e que a união das listas nesses dois campos inclua todas as CPUs do nó.

cpu.balanceIsolated Opcional. Mutável. Booleano. Padrão: true. Esse campo especifica se o conjunto de CPUs isoladas está qualificado para o balanceamento de carga automático de cargas de trabalho nas CPUs. Quando você define esse campo como false, suas cargas de trabalho precisam atribuir cada linha de execução explicitamente a uma CPU específica para distribuir a carga entre as CPUs. Com atribuições de CPU explícitas, você consegue o desempenho mais previsível para cargas de trabalho garantidas, mas isso aumenta a complexidade das cargas de trabalho.
cpu.globallyEnableIRQLoadBalancing Obrigatório. Mutável. Booleano. Padrão: true. Esse campo especifica se o balanceamento de carga de solicitação de interrupção (IRQ, na sigla em inglês) é ativado para o conjunto de CPUs isoladas.

Configuração de memória

Propriedade Descrição
defaultHugePageSize Opcional. Mutável. Enumeração: 1G ou 2M. Esse campo define o tamanho padrão de um enormepage nos parâmetros de inicialização do kernel. Grandes páginas são alocadas no momento da inicialização, antes que a memória fique fragmentada. É importante notar que definir o tamanho padrão de páginas enormes como 1G remove todos os 2 milhões de pastas relacionadas do nó. Um tamanho de página enorme padrão de 1G impede a configuração de 2 milhões de páginas enormes no nó.
pages Opcional. Mutável. Número inteiro. Esse campo especifica o número de páginas enormes a serem criadas durante a inicialização. Esse campo aceita uma matriz de páginas. Verifique a memória disponível para os nós antes de especificar páginas enormes. Não solicite mais páginas enormes do que o necessário nem reserve toda a memória para páginas enormes. Suas cargas de trabalho também precisam de memória padrão.

Seleção de nó

Propriedade Descrição
nodeSelector Obrigatório. Mutável. Esse campo sempre requer o rótulo do nó de trabalho do Kubernetes, node-role.kubernetes.io/worker:"", que garante que o ajuste de desempenho seja feito apenas nos nós de trabalho. Esse campo usa um rótulo de nó opcional como par de chave-valor. Os identificadores de pares de chave-valor são usados para selecionar nós de trabalho específicos com rótulos correspondentes. Quando os rótulos nodeSelector correspondem aos rótulos em um nó de trabalho, o perfil de desempenho é aplicado a esse nó. Se você não especificar um rótulo de chave-valor no perfil, ele será aplicado a todos os nós de trabalho no cluster.

Por exemplo, o nodeSelector a seguir especifica que o perfil de ajuste é aplicado apenas aos nós de trabalho com rótulos app: database correspondentes:


...
spec:
  nodeSelector:
    app: database
    node-role.kubernetes.io/worker: ""
  ...

Configuração do Kubelet

Propriedade Descrição
topologyManagerPolicy Opcional. Mutável. Enumeração: none, best-effort, restricted ou single-numa-node. Padrão: best-effort. Este campo especifica a política do gerenciador de topologia do Kubernetes usada para alocar recursos para suas cargas de trabalho com base na classe de Qualidade de serviço (QoS) atribuída. Para mais informações sobre como as classes de QoS são atribuídas, consulte Configurar a qualidade de serviço para pods.

Operações de perfil

Propriedade Descrição
paused Opcional. Mutável. Booleano. Defina paused como true para impedir temporariamente que os controladores de DaemonSet ajustem os nós selecionados.
updateStrategy Opcional. Mutável. Especifica a estratégia para aplicar mudanças de configuração de ajuste aos nós selecionados.
updateStrategy.rollingUpdateMaxUnavailalble Opcional. Mutável. Número inteiro. Padrão: 1. Especifica o número máximo de nós que podem ser ajustados ao mesmo tempo. Esse campo só é aplicado quando type está definido como rolling.
updateStrategy.type Opcional. Mutável. Enumeração: batch ou rolling. Padrão: rolling. Especifica como aplicar atualizações de perfil aos nós selecionados. Se você quiser aplicar a atualização a todos os nós selecionados ao mesmo tempo, defina type como batch. Por padrão, as atualizações são lançadas sequencialmente para nós individuais, uma após a outra.

Verificar status

Depois que o recurso personalizado PerformanceTuningProfile é criado ou atualizado, um controlador ajusta os nós selecionados com base na configuração fornecida no recurso. Para verificar o status de PerformanceTuningProfile, estamos expondo o seguinte campo em Status:

Propriedade Descrição
conditions A condição representa as observações mais recentes disponíveis do estado atual do recurso de perfil.
conditions.lastTransitionTime Sempre devolvido. String (no formato data-hora). Mostra a última vez que a condição passou de um status para outro. Esse tempo geralmente indica quando a condição subjacente mudou. Se essa hora não for conhecida, a hora indicará quando o campo da API foi alterado.
conditions.message Opcional. String. Uma mensagem legível indicando detalhes sobre a transição. Este campo pode estar vazio.
conditions.observedGeneration Opcional. Número inteiro. Se definido, esse campo representa a metadata.generation em que a condição foi definida. Por exemplo, se metadata.generation for 12, mas status.condition[x].observedGeneration for 9, a condição estará desatualizada em relação ao estado atual da instância.
conditions.reason Obrigatório. String. O motivo da última transição de condição.
conditions.status Obrigatório. Status da condição: True, False ou Unknown.
conditions.type Obrigatório. O tipo é o tipo de condição: Stalled ou Reconciling.
readyNodes O número de nós em que o perfil de ajuste foi aplicado com sucesso.
reconcilingNodes O número de nós selecionados (ou selecionados anteriormente) que estão em processo de reconciliação com o perfil de ajuste mais recente pelo DaemonSet nodeconfig-controller-manager.
selectedNodes O número de notas selecionadas. Ou seja, o número de nós que correspondem ao seletor de nós para esse recurso personalizado PerformanceTuningProfile.

A seguir