Contexto
Fomos indicados por um parceiro para auxiliar uma grande empresa de e-commerce que estava enfrentando problemas em seu cluster AKS. Há pelo menos uma semana o ambiente "caia" e não conseguiam identificar o motivo. O suporte da Microsoft já estava envolvido e havia até engenheiros no caso. Ou seja, o problema estava movimentando toda equipe de TI.
O relato do cliente era que por volta das 15h todos os dias o sistema apresentava falhas:
- Aplicações paravam de responder
- Partes da plataforma ficavam indisponíveis
- Uma aplicação .NET perdia conexão com o SignalR
Já havia uma war room investigando a parte de rede.
A primeira hipótese era que o problema estivesse relacionado ao SignalR, visto que diversos logs indicavam perda de conexão. Era uma aplicação monolítica, crítica para o negócio e servia como principal ponto de entrada do sistema, o que reforçou o direcionamento inicial da equipe para uma investigação de rede.
Investigação
Ingressarmos no problema, mas foi criado outra war room. Buscamos primeiro entender o funcionamento do ambiente e as relações entre as aplicações.
Felizmente, o cluster já estava sendo monitorado via Datadog (A pedido da Microsoft), o que nos permitiu coletar insights e não precisamos configurar tudo do zero.
Durante nossa avaliação, os próprios desenvolvedores comentaram que os logs de desconexão do SignalR não eram novos. Ou seja, eram comuns, porém, como estavam num momento de turbulencia, qualquer alerta começava a ser interpretado como causa raiz (procurando pelo em ovo).
Primeira Pergunta
Pedimos ao time um horário exato em que o problema ocorreu.
A resposta: 15h.
Solicitamos então a abertura da telemetria dos Pods nesse intervalo, comparando uma aplicação crítica com outra não crítica.
- Os Pods pareciam saudáveis: CPU e memória estáveis.
- Porém, o comportamento estava visivelmente lento.
Subindo o nível (Node)
Se o POD está lento mas aparentemente saudável, então quem está doente é o Node.
Abrimos métricas do Node onde o POD estava alocado.
Resultado: CPU do Node em 100%.
Nesse momento encontramos o caminho da causa.
Eliminação de hipóteses
Verificamos se o Node possuía:
- Antivírus instalado manualmente
- Agentes externos não gerenciados pelo cluster
- Workloads de monitoramento indevidos
Perguntas estranhas? Sim, mas é bem comum empresas grandes usarem Gold Images para o cluster. Para nossa sorte, tudo descartado.
Ou seja:
Era algum workload do próprio cluster que estava consumindo toda a CPU.
Descoberta
Ao inspecionar os Deployments do cluster, identificamos:
- Deployments sem limits de CPU, ou
- Limites extremamente desbalanceados, como:
- limit = 16 vCPU
- request = 0.5 vCPU
Um dos serviços em especial realizava cálculos pesados e estava com limit de CPU bem alto, ele podia utilizar todos os cores disponíveis do Node.
Causa Raiz
Durante picos de uso, esse POD consumia 100% da CPU do Node.
Consequências:
- Os demais Pods recebiam CPU throttling
- Health checks começavam a falhar
- Aplicações eram reiniciadas
- O problema se espalhava, causando efeito cascata em todo o cluster
Resumo da ópera
No fim, tratava-se de mais um caso clássico de workloads sem governança de recursos. E aqui entra um ponto importante: nosso time não olha o problema apenas pela ótica de infraestrutura ou somente pela ótica de desenvolvimento, nós transitamos pelos dois lados.
Enquanto a maior parte da war room estava presa ao log de desconexão do SignalR, nós voltamos alguns passos e buscamos entender como as aplicações se relacionavam dentro do cluster. Só assim foi possível determinar a causa raiz.
Essa é a diferença de um time que não só faz DevOps, mas que também desenvolve, instrumenta, mede e depura o ciclo inteiro! Do código ao node do cluster.