Otimize o desempenho do nó

Uma forma de melhorar o desempenho das aplicações baseadas em contentores é aumentar os recursos do cluster adicionando nós ou recursos, como CPUs ou memória, aos nós. No entanto, esta abordagem pode tornar-se dispendiosa. Ajustar os nós do cluster para um melhor desempenho ajuda a otimizar a utilização de recursos para as suas cargas de trabalho de forma rentável. Este documento descreve como usar o operador de otimização do desempenho para otimizar os nós de trabalho de modo a otimizar o desempenho da carga de trabalho para o Google Distributed Cloud.

Para tirar o máximo partido do hardware e software subjacentes, diferentes tipos de aplicações, especialmente aplicações de alto desempenho, beneficiam da otimização das definições dos nós, como as seguintes:

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

Com o operador de otimização do desempenho, configura as definições de desempenho ao nível do nó criando recursos personalizados do Kubernetes que aplicam configurações de desempenho. Seguem-se as vantagens:

  • Interface de configuração única e unificada: com o operador de otimização do desempenho, atualiza um ou mais manifestos que podem ser aplicados a nós de trabalho com seletores de nós.PerformanceTuningProfile Não precisa de configurar cada nó individualmente com várias definições de configuração e políticas. Esta abordagem permite-lhe gerir as configurações ao nível do nó e do contentor de forma única e unificada.

  • Persistência e fiabilidade: também tem toda a fiabilidade que o Kubernetes oferece com a sua arquitetura de alta disponibilidade. Pode atualizar os recursos personalizados do PerformanceTuningProfile sempre que quiser, e as respetivas definições persistem nas principais operações de cluster, como as atualizações.

O operador de otimização do desempenho funciona orquestrando as seguintes funcionalidades e ferramentas do Kubernetes e do sistema operativo (SO) relacionadas com o desempenho:

Para evitar conflitos, quando usa o operador de otimização do desempenho, recomendamos que não use as ferramentas e as funcionalidades do Kubernetes e do SO mencionadas anteriormente de forma independente.

Pré-requisitos e limitações

Seguem-se os pré-requisitos e as limitações para usar o operador de otimização do desempenho:

  • Apenas Red Hat Enterprise Linux (RHEL): o operador de otimização do desempenho é suportado para nós que executam apenas versões suportadas do RHEL.

  • Cluster de utilizador ou híbrido com nós de trabalho: o operador de otimização do desempenho é suportado para utilização com nós de trabalho apenas em clusters de utilizador ou híbridos. A utilização do operador de otimização do desempenho para otimizar os nós do plano de controlo não é suportada. O operador de otimização do desempenho usa um seletor de nós para determinar como aplicar perfis de otimização. Para garantir que os perfis de otimização são aplicados apenas aos nós de trabalho, o nodeSelector em cada recurso personalizado do perfil tem de incluir a etiqueta de nó de trabalho padrão node-role.kubernetes.io/worker: "". Se o nodeSelector num perfil de otimização corresponder às etiquetas num nó do plano de controlo, esse nó não é otimizado e é definida uma condição de erro. Para mais informações sobre as condições de erro, consulte o artigo Verificar estado. Certifique-se de que o cluster está a funcionar corretamente antes de instalar o Performance Tuning Operator e aplicar perfis de otimização.

  • TuneD 2.22.0: o operador de otimização do desempenho requer a pré-instalação da versão 2.22.0 do TuneD nos nós de trabalho que quer otimizar. Para mais informações sobre o TuneD, incluindo instruções de instalação, consulte o artigo Introdução ao TuneD na documentação do Red Hat Enterprise Linux. O Performance Tuning Operator usa o TuneD com o perfil cpu-partitioning. Se não tiver este perfil, pode instalá-lo com o seguinte comando:

    dnf install -y tuned-profiles-cpu-partitioning
    
  • Requisitos de recursos da carga de trabalho: para tirar o máximo partido do ajuste de desempenho, deve compreender bem os requisitos de memória e CPU (pedidos e limites de recursos) das suas cargas de trabalho.

  • Recursos de nós disponíveis: encontre os recursos de CPU e memória para os seus nós. Pode obter informações detalhadas sobre a CPU e a memória do seu nó nos ficheiros /proc/cpuinfo e /proc/meminfo, respetivamente. Também pode usar kubectl get nodes para obter a quantidade de recursos de computação e memória (status.allocatable) que um nó de trabalho tem disponíveis para Pods.

  • Requer esgotamento: como parte do processo de otimização, o operador de otimização do desempenho esgota primeiro os nós e, em seguida, aplica um perfil de otimização. Como resultado, os nós podem comunicar um estado NotReady durante o ajuste do desempenho. Recomendamos que use a estratégia de atualização contínua (spec.updateStrategy.type: rolling) em vez de uma atualização em lote para minimizar a indisponibilidade da carga de trabalho.

  • Requer reinício: para que as alterações de otimização de nós entrem em vigor, o operador de otimização do desempenho reinicia o nó após aplicar o perfil de otimização.

Instale o operador de otimização do desempenho

O operador de otimização do desempenho consiste principalmente em dois controladores (uma implementação e um DaemonSet) que interagem entre si para otimizar os nós com base nas definições do seu perfil. O operador de otimização do desempenho não está instalado com o Google Distributed Cloud por predefinição. Transfere os manifestos do operador de otimização do desempenho do Cloud Storage e usa kubectl apply para criar recursos do operador de otimização do desempenho no cluster.

Para ativar o ajuste de desempenho com valores predefinidos para o cluster:

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

  2. A partir do diretório performance-tuning, transfira o pacote do operador de otimização do desempenho mais recente a partir do contentor de lançamento do Cloud Storage:

    gcloud storage cp gs://anthos-baremetal-release/node-performance-tuning/0.1.0-gke.47 . --recursive
    

    Os ficheiros transferidos incluem manifestos para a performance-tuning-operator implementação e o nodeconfig-controller-manager DaemonSet. Também estão incluídos manifestos para funções relacionadas, como o controlo de acesso baseado em funções (CABF) e o controlo de admissão dinâmico.

  3. Como utilizador raiz, aplique todos os manifestos do operador de otimização do desempenho recursivamente ao seu cluster de utilizador (ou híbrido):

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

    Depois de o Deployment e o DaemonSet serem criados e estarem em execução, a sua única interação é editar e aplicar PerformanceTuningProfilemanifestos.

Reveja os requisitos de recursos para as suas cargas de trabalho

Antes de poder otimizar os seus nós, tem de compreender os requisitos de recursos de computação e memória das suas cargas de trabalho. Se os nós de trabalho tiverem recursos suficientes, os nós podem ser otimizados para fornecer memória garantida (standard e hugepages) para as suas cargas de trabalho na classe de Qualidade de Serviço (QoS) garantida.

O Kubernetes atribui classes de QoS a cada um dos seus pods com base nas restrições de recursos que especificar para os contentores associados. Em seguida, o Kubernetes usa as classes de QoS para determinar como agendar os seus pods e contentores, e alocar recursos aos seus workloads. Para tirar o máximo partido da otimização de nós para as suas cargas de trabalho, estas têm de ter definições de pedidos ou limites de recursos de CPU ou memória.

Para lhe ser atribuída uma classe de QoS garantida, os seus pods têm de cumprir os seguintes requisitos:

  • Para cada contentor no agrupamento:
    • Especifique valores para pedidos de recursos de memória (spec.containers[].resources.requests.memory) e limites (spec.containers[].resources.limits.memory).
    • O valor dos limites de memória tem de ser igual ao valor dos pedidos de memória.
    • Especifique valores para os pedidos de recursos de CPU (spec.containers[].resources.requests.cpu) e os limites (spec.containers[].resources.limits.cpu).
    • O valor dos limites de CPU tem de ser igual ao valor dos pedidos de CPU.

O excerto da especificação do pod seguinte mostra as definições de recursos da CPU que cumprem os requisitos da classe de QoS garantida:

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

Quando obtém detalhes do pod com kubectl get pods, a secção status deve incluir a classe de QoS atribuída, conforme mostrado no exemplo seguinte:

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 o artigo Classes de qualidade de serviço de pods na documentação do Kubernetes. Para obter instruções sobre como configurar os seus pods e contentores para que lhes seja atribuída uma classe de QoS, consulte o artigo Configure a qualidade de serviço para pods

Requisitos da CPU

Ao otimizar um nó, pode especificar um conjunto de núcleos da CPU reservados (spec.cpu.reservedCPUs) para executar daemons do sistema Kubernetes, como o kubelet e o tempo de execução do contentor. Este mesmo conjunto de CPUs reservadas também executa os daemons do sistema operativo, como sshd e udev. Os restantes núcleos da CPU são atribuídos como isolados. As CPUs isoladas destinam-se a aplicações limitadas pela CPU, que requerem tempo de CPU dedicado sem interferência de outras aplicações ou interrupções da rede ou de outros dispositivos.

Para agendar um Pod nas CPUs isoladas de um nó trabalhador:

  • Configure o Pod para uma qualidade de serviço (QoS) garantida.

  • Os requisitos e os limites da CPU têm de ser especificados em números inteiros. Se especificar recursos parciais da CPU na especificação do pod, como cpu: 0.5 ou cpu: 250m (250 milicores), não é possível garantir o agendamento.

Requisitos de memória

Quando ajusta um nó com o operador de ajuste de desempenho, pode criar páginas grandes e associá-las aos nós de acesso à memória não uniforme (NUMA) na máquina. Com base nas definições de nós e pods, os pods podem ser agendados com afinidade de nós NUMA.

Crie um perfil de otimização do desempenho

Depois de instalar o Performance Tuning Operator, interage apenas com o cluster que executa as suas cargas de trabalho. Cria PerformanceTuningProfilerecursos personalizados diretamente no cluster de utilizadores ou no cluster híbrido e não no cluster de administrador. Cada recurso PerformanceTuningProfileconté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 aos quais o perfil de otimização é aplicado. Para aplicar um perfil a um nó, coloca a etiqueta do par de chave-valor correspondente no nó. É aplicado um perfil de otimização aos nós que têm todas as etiquetas especificadas no campo nodeSelector.

Pode criar vários recursos PerformanceTuningProfile num cluster. Se mais do que um perfil corresponder a um determinado nó, é definida uma condição de erro no status do recurso personalizado PerformanceTuningProfile. Para mais informações sobre a secção status, consulte o artigo Verificar estado.

Defina o espaço de nomes do seu recurso personalizado como PerformanceTuningProfilekube-system.

Para otimizar um ou mais nós de trabalho:

  1. Edite o PerformanceTuningProfilemanifesto.

    Para ver informações sobre cada campo no manifesto e um manifesto de exemplo, consulte a PerformanceTuningProfilereferência de recursos.

  2. (Opcional) Para os nós de trabalho aos quais está a aplicar um perfil, adicione etiquetas que correspondam ao par de chave-valor spec.nodeSelector.

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

  3. Aplique o manifesto ao seu cluster.

    kubectl apply -f PROFILE_MANIFEST --kubeconfig KUBECONFIG
    

    Substitua o seguinte:

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

Remova um perfil de otimização

Para repor um nó para o estado original sem ajuste:

  1. Elimine o recurso personalizado PerformanceTuningProfile do cluster.

  2. Atualize ou remova as etiquetas no nó para que não seja selecionado novamente pelo perfil de otimização.

Se tiver vários perfis de otimização associados ao nó, repita os passos anteriores, conforme necessário.

Pause um perfil de otimização

Se precisar de realizar manutenção no cluster, pode pausar temporariamente a otimização editando o recurso personalizado PerformanceTuningProfile. Recomendamos que pause a otimização antes de realizar operações de cluster críticas, como uma atualização do cluster.

A aplicação de um perfil sem êxito é outro caso em que pode pausar a otimização. Se o processo de otimização não for bem-sucedido, o controlador pode continuar a tentar otimizar o nó, o que pode resultar no reinício repetido do nó. Se observar que o estado do nó alterna entre o estado pronto e não pronto, pause a otimização para poder recuperar do estado danificado.

Para pausar a otimização:

  1. Edite o manifesto de recursos personalizados PerformanceTuningProfile para definir spec.paused como true.

  2. Use kubectl apply para atualizar o recurso.

Quando a otimização do desempenho está pausada, o controlador do operador de otimização do desempenho interrompe todas as respetivas operações. A pausa evita o risco de as operações do controlador do operador de otimização do desempenho entrarem em conflito com as operações do controlador do Google Distributed Cloud.

PerformanceTuningProfile referência de recurso

Esta secção descreve cada um dos campos no recurso personalizado.PerformanceTuningProfile Este recurso é usado para criar um perfil de otimização para um ou mais nós do cluster. Todos os campos no recurso são mutáveis após a criação do perfil. Os perfis têm de estar no espaço de nomes kube-system.

O seguinte manifesto do perfil de exemplo numa para nós com 8 núcleos de CPU especifica as seguintes atribuições de recursos:

  • 4 núcleos da CPU (0-3) estão reservados para a sobrecarga do sistema Kubernetes.

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

  • Por predefinição, a memória do nó é dividida em páginas de 2 MiB, em vez das páginas padrão de 4 KiB.

  • São reservadas 10 páginas de memória com um tamanho de 1 GiB para utilização pelo nó NUMA 0.

  • 5 páginas de memória com um tamanho de 2 MiB são reservadas para utilização pelo nó NUMA 1.

  • O Topology Manager usa a política de melhor esforço para agendar 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

Pode obter a definição de recurso personalizado PerformanceTuningProfile relacionada do grupo anthos.gke.io no seu cluster. A definição do recurso personalizado é instalada assim que a anotação da funcionalidade de pré-visualização é adicionada ao recurso do cluster autogerido.

Configuração da CPU

Propriedade Descrição
cpu.reservedCPUs Obrigatório. Mutável. String. Este campo define um conjunto de núcleos da CPU a reservar para os daemons do sistema Kubernetes, como o kubelet, o tempo de execução do contentor e o detetor de problemas do nó. Estes núcleos da CPU também são usados para os daemons do sistema operativo (SO), como o sshd e o udev.

O campo cpu.reservedCPUs aceita uma lista de números de CPU ou intervalos de números de CPU. Certifique-se de que a lista de CPUs não se sobrepõe à lista especificada com cpu.isolatedCPUs. A união das CPUs indicadas nestes dois campos tem de incluir todas as CPUs do nó.

cpu.isolatedCPUs Opcional. Mutável. String. O campo cpu.isolatedCPUs define um conjunto de CPUs que são usadas exclusivamente para aplicações sensíveis ao desempenho. O CPU Manager agenda contentores 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 são executadas nas CPUs isoladas, configure os pods com a classe de QoS garantida e atribua um recurso de CPU ao pod ou ao contentor. Para o agendamento de pods garantido, tem de especificar unidades de CPU inteiras e não recursos de CPU parciais (cpu: "0.5").
apiVersion: v1
kind: Pod
...
spec:
  containers:
  ...
    resources:
      limits:
        cpu: "1"
      requests:
        cpu: "1"
  ...

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

cpu.balanceIsolated Opcional. Mutável. Booleano. Predefinição: true. Este campo especifica se o conjunto de CPUs isolado é elegível para o equilíbrio de carga automático das cargas de trabalho nas CPUs. Quando define este campo como false, as suas cargas de trabalho têm de atribuir cada thread explicitamente a uma CPU específica para distribuir a carga pelas CPUs. Com as atribuições explícitas de CPU, obtém o desempenho mais previsível para cargas de trabalho garantidas, mas adiciona mais complexidade às suas cargas de trabalho.
cpu.globallyEnableIRQLoadBalancing Obrigatório. Mutável. Booleano. Predefinição: true. Este campo especifica se o balanceamento de carga do pedido de interrupção (IRQ) deve ser ativado ou não para o conjunto de CPUs isolado.

Configuração da memória

Propriedade Descrição
defaultHugePageSize Opcional. Mutável. Enumeração: 1G ou 2M. Este campo define o tamanho da página enorme predefinido nos parâmetros de arranque do kernel. As páginas grandes são atribuídas no momento do arranque, antes de a memória ficar fragmentada. É importante ter em atenção que a definição do tamanho predefinido das páginas enormes para 1G remove todas as pastas relacionadas com 2M do nó. Um tamanho de página enorme predefinido de 1 G impede a configuração de páginas enormes de 2 M no nó.
pages Opcional. Mutável. Número inteiro. Este campo especifica o número de páginas grandes a criar no momento do arranque. Este campo aceita uma matriz de páginas. Verifique a memória disponível para os seus nós antes de especificar páginas grandes. Não peça mais páginas grandes do que o necessário e não reserve toda a memória para páginas grandes. As suas cargas de trabalho também precisam de memória padrão.

Seleção de nós

Propriedade Descrição
nodeSelector Obrigatório. Mutável. Este campo requer sempre a etiqueta do nó trabalhador do Kubernetes, node-role.kubernetes.io/worker:"", que garante que a otimização do desempenho é feita apenas nos nós trabalhadores. Este campo recebe uma etiqueta de nó opcional como um par de chave-valor. As etiquetas de pares de chave-valor são usadas para selecionar nós de trabalho específicos com etiquetas correspondentes. Quando as etiquetas nodeSelector correspondem às etiquetas num nó de trabalho, o perfil de desempenho é aplicado a esse nó. Se não especificar uma etiqueta de chave-valor no seu perfil, esta é aplicada a todos os nós de trabalho no cluster.

Por exemplo, o seguinte nodeSelector especifica que o perfil de otimização é aplicado apenas a nós de trabalho com etiquetas 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. Predefinição: best-effort. Este campo especifica a política do Topology Manager do Kubernetes usada para atribuir recursos aos seus 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 o artigo Configure a qualidade de serviço para pods.

Operações do perfil

Propriedade Descrição
paused Opcional. Mutável. Booleano. Defina paused como true para impedir temporariamente que os controladores DaemonSet ajustem os nós selecionados.
updateStrategy Opcional. Mutável. Especifica a estratégia para aplicar alterações de configuração de otimização aos nós selecionados.
updateStrategy.rollingUpdateMaxUnavailalble Opcional. Mutável. Número inteiro. Predefinição: 1. Especifica o número máximo de nós que podem ser ajustados em simultâneo. Este campo aplica-se apenas quando type está definido como rolling.
updateStrategy.type Opcional. Mutável. Enumeração: batch ou rolling. Predefinição: rolling. Especifica como aplicar atualizações de perfis aos nós selecionados. Se quiser aplicar a atualização a todos os nós selecionados em simultâneo, defina type como batch. Por predefinição, as atualizações são implementadas sequencialmente em nós individuais, um após o outro.

Verificar estado

Após a criação ou a atualização do recurso personalizado PerformanceTuningProfile, um controlador ajusta os nós selecionados com base na configuração fornecida no recurso. Para verificar o estado do PerformanceTuningProfile, estamos a expor o seguinte campo em Status:

Propriedade Descrição
conditions Condition representa as observações mais recentes disponíveis do estado atual do recurso de perfil.
conditions.lastTransitionTime Sempre devolvido. String (no formato de data/hora). Última vez que a condição passou de um estado para outro. Normalmente, esta hora indica quando a condição subjacente foi alterada. Se essa hora não for conhecida, a hora indica quando o campo da API foi alterado.
conditions.message Opcional. String. Uma mensagem legível que indica detalhes sobre a transição. Este campo pode estar vazio.
conditions.observedGeneration Opcional. Número inteiro. Se estiver definido, este campo representa o metadata.generation com base no qual a condição foi definida. Por exemplo, se metadata.generation for 12, mas status.condition[x].observedGeneration for 9, a condição está desatualizada relativamente ao estado atual da instância.
conditions.reason Obrigatório. String. O motivo da última transição de condição.
conditions.status Obrigatório. Estado 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 aos quais o perfil de otimização foi aplicado com êxito.
reconcilingNodes O número de nós selecionados (ou selecionados anteriormente) que estão em processo de conciliação com o perfil de otimização mais recente pelo DaemonSet nodeconfig-controller-manager.
selectedNodes O número de notas que foram selecionadas. Ou seja, o número de nós que correspondem ao seletor de nós para este recurso personalizado PerformanceTuningProfile.

O que se segue?