Solucionando Gargalos Comuns de Desempenho no Kubernetes

Aprenda a diagnosticar e resolver sistematicamente gargalos comuns de desempenho no Kubernetes, incluindo limitação de CPU, OOMKills de memória e atrasos de agendamento. Este guia fornece comandos acionáveis e melhores práticas para ajustar solicitações de recursos, otimizar o escalonamento do HPA e identificar restrições subjacentes do cluster para garantir o desempenho ideal do aplicativo.

Solucionando Gargalos Comuns de Desempenho no Kubernetes

Problemas de desempenho no Kubernetes raramente se anunciam como "Kubernetes está lento". Você vê uma implantação que trava, uma API que de repente retorna erros 5xx, uma fila que para de drenar ou pods que parecem saudáveis enquanto os usuários reclamam de latência. O cluster é apenas uma parte dessa história, mas é a parte que você pode inspecionar com um conjunto consistente de comandos.

O truque é evitar pular direto para o tamanho do nó ou a contagem de réplicas. Primeiro, decida que tipo de gargalo você tem: limitação de CPU, pressão de memória, atraso de agendamento, escalonamento lento, latência de rede, latência de armazenamento ou um aplicativo que está simplesmente fazendo mais trabalho do que o esperado.

Fase 1: Identificando os Sintomas

Antes de mergulhar em componentes específicos, defina claramente a degradação de desempenho observada. Os sintomas comuns geralmente se enquadram em uma destas categorias:

  • Implantações/Atualizações Lentas: A criação de pods leva um tempo excessivo ou as atualizações contínuas param.
  • Aplicativos Não Responsivos: Os pods estão em execução, mas falham ao responder ao tráfego no nível do aplicativo (por exemplo, alta latência, erros 5xx).
  • Picos Altos de Recursos: Picos inexplicáveis de utilização de CPU ou memória em nós ou implantações específicas.
  • Atrasos de Agendamento: Novos pods permanecem no estado Pending indefinidamente.

Fase 2: Diagnosticando Restrições de Recursos (CPU e Memória)

O gerenciamento inadequado de recursos é a causa mais frequente de problemas de desempenho no Kubernetes. Solicitações e limites definidos incorretamente levam a limitação ou OOMKills.

1. Verificando a Utilização e os Limites de Recursos

Comece inspecionando as alocações de recursos para o aplicativo afetado usando kubectl describe e kubectl top.

Verificação Acionável: Compare as requests e limits com o uso real relatado pelos servidores de métricas.

# Obter uso de recursos para todos os pods em um namespace
kubectl top pods -n <namespace>

# Examinar solicitações/limites de recursos para um pod específico
kubectl describe pod <pod-name> -n <namespace>

Inspecione também a carga de trabalho proprietária para entender se o problema afeta um pod ou toda a Implantação:

kubectl get deploy <deployment-name> -n <namespace> -o yaml
kubectl get pods -n <namespace> -l app=<label> -o wide

Se apenas um pod estiver lento e estiver em um nó diferente dos outros, a pressão no nível do nó é mais provável. Se todas as réplicas estiverem lentas, as configurações de recursos, dependências downstream ou o comportamento do aplicativo merecem mais atenção.

2. Limitação de CPU (CPU Throttling)

Se o uso de CPU de um contêiner atingir repetidamente seu limite definido, o kernel o limitará, levando a picos severos de latência, mesmo que o nó em si tenha capacidade disponível. Isso é frequentemente confundido com falta geral de CPU.

Dica de Diagnóstico: Procure respostas de alta latência, mesmo quando kubectl top não mostra 100% de uso de CPU no . A limitação acontece por contêiner.

Para confirmação mais profunda, use seu sistema de métricas se ele expuser métricas de limitação de CPU do contêiner. Em configurações baseadas em Prometheus, as equipes geralmente monitoram métricas como períodos de CPU limitados juntamente com a latência da solicitação. O uso bruto de CPU sozinho pode esconder a limitação porque um contêiner pode ser limitado antes mesmo de parecer usar um núcleo completo do nó.

Resolução:

  • Aumente o limit de CPU se a carga de trabalho exigir legitimamente mais poder de processamento.
  • Se o aplicativo estiver em espera ocupada (busy-waiting), otimize o código do aplicativo em vez de simplesmente aumentar os limites.
  • Considere remover os limites de CPU para alguns serviços sensíveis à latência, mantendo as solicitações de CPU, se isso corresponder à sua política de plataforma. Isso evita a limitação rígida, enquanto ainda fornece ao agendador informações úteis de posicionamento.

3. Pressão de Memória e OOMKills

Se um contêiner exceder seu limite de memória, o Kubernetes inicia uma eliminação por falta de memória (Out-Of-Memory - OOM), reiniciando o contêiner repetidamente.

Diagnóstico: Verifique o status do pod para reinicializações frequentes (verifique a coluna RESTARTS em kubectl get pods) e examine os logs para eventos OOMKilled.

# Verificar eventos recentes para OOMKills
kubectl get events --field-selector involvedObject.name=<pod-name> -n <namespace>

Resolução:

  • Se os OOMKills forem frequentes, aumente imediatamente o limit de memória.
  • Para correções de longo prazo, analise o aplicativo para encontrar e corrigir vazamentos de memória ou reduzir o tamanho do heap.

A memória se comporta de maneira diferente da CPU. A CPU pode ser limitada e o processo continua funcionando lentamente. As violações do limite de memória geralmente terminam com o processo sendo eliminado. Isso faz com que os problemas de memória pareçam incidentes de confiabilidade: reinicializações, conexões perdidas, caches frios e solicitações em andamento com falha.

Melhor Prática: Defina Solicitações com Sabedoria. Certifique-se de que as requests de recursos estejam definidas razoavelmente próximas ao uso mínimo esperado. Se as requests forem muito baixas, o agendador pode superalocar o nó, levando à contenção quando todos os pods atingirem suas demandas simultaneamente.

Fase 3: Investigando Gargalos de Agendamento

Quando os pods permanecem no estado Pending, o problema está na incapacidade do agendador de encontrar um nó adequado.

1. Analisando Pods Pendentes

Use kubectl describe pod em um pod pendente para ler a seção Events. Esta seção geralmente contém uma explicação clara para a falha no agendamento.

Mensagens Comuns do Agendador:

  • 0/3 nodes are available: 3 Insufficient cpu. (Problema de capacidade do nó)
  • 0/3 nodes are available: 3 node(s) had taint {dedicated: infra}, that the pod didn't tolerate. (Incompatibilidade de Taints/Tolerations)
  • 0/3 nodes are available: 1 node(s) had taint {NoSchedule: true}, that the pod didn't tolerate. (Pressão ou manutenção do nó)

2. Saturação de Recursos do Cluster

Se o agendamento estiver atrasado devido à falta de CPU/Memória, o cluster não possui capacidade agregada suficiente.

Resolução:

  • Adicione mais nós ao cluster.
  • Verifique se a utilização do nó não está artificialmente alta devido a solicitações de recursos mal configuradas (consulte a Fase 2).
  • Use o Cluster Autoscaler (CA) se estiver executando em provedores de nuvem para adicionar nós dinamicamente quando os pods pendentes se acumularem.

Se o Cluster Autoscaler estiver habilitado, mas os nós não estiverem sendo adicionados, leia seus logs antes de presumir que o provedor de nuvem está quebrado. O Autoscaler pode se recusar a adicionar nós porque os grupos de nós atingiram seu tamanho máximo, o pod pendente tem restrições que nenhum grupo de nós pode satisfazer ou as cotas impedem novas instâncias.

Fase 4: Problemas de Desempenho em Mecanismos de Escalonamento

O escalonamento automatizado deve reagir rapidamente, mas configurações incorretas no Horizontal Pod Autoscaler (HPA) ou no Vertical Pod Autoscaler (VPA) podem causar problemas.

1. Atraso do Horizontal Pod Autoscaler (HPA)

O HPA depende do Metrics Server para relatar a utilização precisa de CPU/Memória ou métricas personalizadas.

Etapas de Diagnóstico:

  1. Verificar a Saúde do Metrics Server: Certifique-se de que o Metrics Server esteja em execução e acessível.
    kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes"
    
  2. Verificar o Status do HPA: Inspecione a configuração do HPA e os eventos recentes.
    kubectl describe hpa <hpa-name> -n <namespace>
    
    Procure mensagens indicando se a fonte de métricas está indisponível ou se o loop de decisão de escalonamento está funcionando.

Gargalos: Se métricas personalizadas forem usadas, certifique-se de que o provedor de métricas externo esteja funcionando corretamente e relatando dados com frequência suficiente para que o HPA tome decisões úteis.

O HPA é reativo. Ele não sabe que um pico de tráfego está chegando, a menos que sua métrica o reflita. Para cargas de trabalho com picos repentinos, você pode precisar de réplicas mínimas mais altas, métricas personalizadas mais rápidas, escalonamento baseado em fila ou pré-escalonamento antes de eventos conhecidos.

2. Interações do Vertical Pod Autoscaler (VPA)

Embora o VPA ajuste automaticamente as solicitações de recursos, ele pode causar instabilidade de desempenho durante sua fase de ajuste se reiniciar ou redimensionar pods com frequência, especialmente para aplicações com estado que não toleram reinicializações.

Recomendação: Use o VPA no modo Recommender primeiro ou use o updateMode: "Off" para apenas observar recomendações sem aplicação automática, mitigando interrupções de redimensionamento desnecessárias.

Fase 5: Desempenho de Rede e Armazenamento

Quando os recursos de computação parecem bons, a rede ou o armazenamento persistente podem ser o ponto de estrangulamento.

1. Problemas de CNI (Container Network Interface)

Se a comunicação entre pods (especialmente entre nós) for lenta ou falhar intermitentemente, o plugin CNI pode estar sobrecarregado ou mal configurado.

Solução de Problemas:

  • Verifique os logs dos pods do daemonset CNI (por exemplo, Calico, Flannel).
  • Teste a conectividade básica usando ping ou curl entre pods em nós diferentes.

2. Latência de Volume Persistente (PV)

Aplicativos que dependem fortemente de E/S de disco (bancos de dados, sistemas de registro) sofrerão se a latência do Volume Persistente subjacente for alta.

Verificação Acionável: Confirme o tipo de provisionador (por exemplo, AWS EBS gp3 vs. io1) e verifique se o volume atende às especificações de IOPS/throughput necessárias.

Aviso sobre Armazenamento: Nunca execute bancos de dados de alto throughput diretamente em volumes hostPath padrão sem entender as características de desempenho do disco subjacente. Use soluções de armazenamento em nuvem gerenciadas ou provisionadores de armazenamento local de alto desempenho para cargas de trabalho exigentes.

Gargalos no Nível do Nó

Às vezes, todos os pods em um nó ficam mais lentos ao mesmo tempo. Essa é a sua deixa para parar de olhar para uma Implantação e inspecionar o nó.

kubectl describe node <node-name>
kubectl top node <node-name>
kubectl get pods --all-namespaces -o wide | grep <node-name>

Procure por condições MemoryPressure, DiskPressure e PIDPressure. A pressão do disco é fácil de ignorar porque o sintoma do aplicativo pode ser inicialização lenta, falhas na obtenção de imagem ou despejos, em vez de um erro de disco óbvio.

No próprio nó, se você tiver acesso, verifique:

df -h
iostat -x 1
free -h
journalctl -u kubelet --since "30 minutes ago"

Os serviços Kubernetes gerenciados podem limitar o acesso direto ao nó, mas a mesma ideia ainda se aplica: use métricas do provedor, eventos do kubelet e condições do nó para decidir se o nó é o gargalo compartilhado.

Plano de Controle e Pressão da API

A maior parte da latência do aplicativo não é causada pelo servidor da API Kubernetes. Sua solicitação da web geralmente não chama o servidor da API em cada solicitação do usuário. Mas a pressão do plano de controle pode prejudicar o desempenho operacional: implantações lentas, agendamento atrasado, atualizações lentas de endpoints ou controladores ficando para trás.

Os sintomas incluem:

  • Os comandos kubectl são lentos em todo o cluster.
  • As implantações demoram mais do que o normal para criar pods.
  • Os controladores ficam atrás do estado desejado.
  • Os eventos mostram timeouts repetidos da API.

Verifique se o problema afeta o tráfego normal do aplicativo ou as operações do cluster. Se apenas as implantações e o agendamento estiverem lentos, observe a saúde do servidor da API, o comportamento do gerenciador do controlador, os webhooks de admissão e a saúde do etcd em clusters onde você gerencia o plano de controle.

Os webhooks de admissão merecem atenção especial. Um webhook lento ou indisponível pode atrasar a criação de pods mesmo quando os nós têm bastante capacidade. Se uma implantação travar no momento da criação e os eventos mencionarem chamadas de webhook, investigue o serviço de webhook antes de redimensionar os nós.

Uma Ordem Prática de Solução de Problemas

Comece com o sintoma visível ao usuário:

  • Solicitações HTTP lentas: compare a latência do aplicativo, limitação de CPU, reinicializações de memória, latência downstream e caminho de rede.
  • Inicialização lenta do pod: verifique o tempo de obtenção da imagem, eventos de agendamento, tempo de anexação do volume e contêineres de inicialização.
  • Pods pendentes: verifique solicitações, capacidade do nó, taints, afinidade, cotas e limites do autoscaler.
  • Picos periódicos de latência: verifique limitação de CPU, coleta de lixo, vizinhos barulhentos, latência de armazenamento e tempo de escalonamento do HPA.
  • Reinicializações aleatórias: verifique OOMKilled, sondas de vivacidade, pressão do nó e logs do aplicativo do contêiner anterior.

Em seguida, prove ou elimine uma camada de cada vez. Por exemplo, se os picos de latência coincidirem exatamente com a limitação da CPU, você tem uma forte pista. Se os picos de latência acontecerem enquanto CPU, memória, rede e armazenamento parecem calmos, o gargalo pode estar dentro do aplicativo ou em um serviço downstream fora do Kubernetes.

Ajuste de Solicitação e Limite Sem Adivinhação

Configurações de recursos ruins criam muitos problemas de desempenho:

  • Solicitações muito baixas: o agendador empacota muitos pods ocupados no mesmo nó.
  • Solicitações muito altas: os pods permanecem pendentes mesmo que o uso real seja modesto.
  • Limites de CPU muito baixos: aplicativos sensíveis à latência são limitados.
  • Limites de memória muito baixos: os contêineres são eliminados em vez de desacelerar.
  • Nenhuma solicitação: o agendamento se torna menos previsível e as cargas de trabalho críticas podem competir mal com vizinhos barulhentos.

Use métricas de produção recentes como ponto de partida e, em seguida, deixe espaço para picos normais. Para cargas de trabalho Java, Node.js, Go, Python e semelhantes a banco de dados, o comportamento da memória pode ser muito diferente, portanto, evite copiar limites de um serviço para outro apenas porque o tamanho da imagem do contêiner parece semelhante.

Próximos Passos

As melhores investigações de desempenho do Kubernetes são chatas de uma boa maneira: defina o sintoma, verifique o pod, verifique o nó, verifique o escalonamento, depois verifique a rede e o armazenamento. kubectl describe e kubectl top são apenas o começo, mas geralmente indicam qual direção vale a pena seguir.

  1. Implemente Resource Quotas robustas para evitar que vizinhos barulhentos privem aplicativos críticos de recursos.
  2. Revise regularmente as contagens de reinicialização de pods para detectar OOMs sutis ou comportamento de aplicativo com falha no início.
  3. Utilize painéis Prometheus/Grafana que rastreiam especificamente métricas de limitação de CPU, não apenas o uso bruto.