Leo

Sobre tecnologia...

Histórias de terror de um engenheiro de software | Episodio 2: Da Idempotência ao Caos.

3 months ago · 3 MIN READ

Introdução

Este post é baseado em um post mortem de um incidente real de tecnologia, documentado após a resolução completa do problema. Removemos completamente quaisquer referências a pessoas reais e a empresas reais. O objetivo é focar no aprendizado e entreter com uma bela história

Detalhamento do incidente

Na época em que esse incidente ocorreu a empresa onde eu trabalhama mantinha um API Gateway para ser o pondo de entrada para o sistema, condo do mundo externo. Esse Gateway não era uma ferramenta proprietária e sim um Gateway feito em NodeJS onde que era mantido pelo priprio time e claro precisava ser monitorado devidamente como qualquer outro componente do sistema.

Fazia parte do nosso monitoramento um alerta no Slack que havia em cada componente do sistema que era executado em um container Docker, alerta é disparado quando um container fica no estado "unhealth", como o leitor já deve estar imaginando recebemos esse alerta referente ao nosso API Gateway.

O incidente em si não é de extrema severidade pois quando isso ocorre o container é rapidamente reiniciado pelo orquestrador nos deixando com menos de 1 minuto de "downtime".


Comunicação do incidente

Durante o período do incidente, o time técnico atuou de forma contínua para investigar os sintomas apresentados, identificar a causa raiz e restabelecer a estabilidade do serviço.

A comunicação interna foi realizada entre os times responsáveis pelo middleware, infraestrutura e banco de dados, permitindo a consolidação de evidências técnicas e o alinhamento das ações de mitigação.


Detalhamento do incidente

A indisponibilidade foi causada por uma combinação de fatores técnicos:

  • Uma falha de timeout no cyberhook;
  • Um endpoint de webhook lento, operando próximo ao limite de timeout;
  • Possível ausência de idempotência nesse endpoint.

Esses fatores, combinados, provocaram um loop de inserções no MongoDB, especificamente na collection responsável pelo calendário de uma única empresa. Como consequência, foram gerados mais de 10 milhões de registros indevidos nessa collection.

A consulta responsável por retornar esses dados era executada no middleware. Sempre que a empresa afetada acessava o calendário, o cursor do Mongoose carregava uma quantidade massiva de registros na memória.

Esse comportamento levava o container a atingir o limite de memória, causando:

  • Travamento da aplicação;
  • Falha no health check;
  • Reinicialização automática pelo orquestrador.

O ciclo se repetia a cada nova tentativa de acesso ao calendário por parte da empresa impactada, configurando as quedas recorrentes observadas ao longo da semana.


Tratamento do incidente

A normalização começou a avançar no dia 19/03, após o restabelecimento das métricas no Grafana no período da manhã.

Paralelamente, melhorias recentes de logging implementadas no projeto do Middleware permitiram identificar uma query que era executada consistentemente nos momentos de indisponibilidade.

A partir dessa descoberta:

  1. Foi analisado um pico ocorrido na segunda-feira pela manhã.
  2. Os dados foram cruzados com os registros de login.
  3. Identificou-se uma correlação entre o acesso de uma administradora específica e as quedas do middleware.

Essa empresa possuía milhões de registros indevidos na coleção de lembretes, o que fazia com que o Node.js não suportasse o volume de dados retornado na consulta ao banco.

Após a identificação do problema:

  • Os dados inconsistentes foram excluídos;
  • A sincronização correta foi executada novamente;
  • O serviço foi restabelecido e estabilizado.

Análise e Encerramento do Incidente

O incidente evidenciou pontos importantes de melhoria tanto em nível técnico quanto organizacional. A seguir, os principais planos de ação definidos:

  1. Organização das chamadas de emergência\ Para evitar ruído e insegurança durante incidentes, apenas líderes passarão a participar das chamadas emergenciais.

  2. Reversão de ajustes emergenciais de infraestrutura\ O aumento temporário de instâncias e limites de container será revertido após estabilização.

  3. Revisão do limite de memória do Node.js\ O limite ampliado durante a investigação será restabelecido ao padrão anterior.

  4. Análise da idempotência no fluxo de inserts no MongoDB\ Identificar e corrigir a parte do fluxo que permitiu o comportamento não idempotente.

  5. Teste de memória do middleware\ Implementar mecanismos para que consumo excessivo seja tratado na camada da aplicação, evitando a morte do container.

  6. Timeout de consultas no middleware\ Implementação via connection string.

  7. Timeout de consultas no cluster\ Ajustes para evitar execuções prolongadas.

  8. Revisão do timeout do cyberhook\ Garantir que nunca ultrapasse o limite do heartbeat.

  9. Redução progressiva do timeout do cyberhook\ Ajuste gradual até atingir 1 segundo.

  10. Idempotência via plataforma (after middleware no cyberlock)\ Implementação estrutural para prevenir recorrência do problema.

  11. Alerta de HD em todas as instâncias\ Evitar indisponibilidade de ferramentas de monitoramento.

  12. Investigação da causa raiz de espaço em disco no Grafana/Zabbix


Conclusão

Este incidente reforça a importância de:

  • Garantir idempotência em integrações externas;
  • Definir timeouts coerentes e consistentes entre serviços;
  • Implementar mecanismos de proteção contra consultas massivas;
  • Manter observabilidade plenamente funcional;
  • Ter processos claros de resposta a incidentes.

Apesar da severidade e da duração do evento, a identificação da causa raiz e as ações corretivas implementadas aumentaram significativamente a resiliência da arquitetura e a maturidade operacional do time.

São Paulo, 27 de Março de 2024

···

Leonardo Lemos


comments powered by Disqus


Proudly powered by Canvas · Sign In