Blog

O arquivo de swap que faltava e travou os nossos servidores

Em 24 de setembro, um dos nossos servidores de produção parou de responder. O balanceador de carga o marcou como não saudável e a nossa ferramenta de comandos remotos não conseguia alcançá-lo, mas nada tinha travado e nada tinha sido morto por usar memória demais. O servidor estava em thrashing: sem espaço de swap e com contêineres autorizados a usar mais memória do que a máquina tinha, o Linux passava o tempo despejando e relendo os arquivos de que precisava para rodar, e quase não avançava. Adicionar um arquivo de swap de 2 GB em cada servidor resolveu. A lição mais interessante foi sobre health checks.

Como era o "travamento"

  • Os health checks do balanceador de carga expiravam nesse servidor.
  • Os comandos enviados pelo AWS Systems Manager ficavam em "Pendente" e nunca rodavam.
  • Não havia morte por falta de memória nos logs. Nenhum processo tinha morrido.

Uma semana antes, tínhamos movido a produção para servidores ARM menores com 2 GB de RAM cada. Nosso servidor de testes, ainda menor, tinha travado da mesma forma ao descompactar uma imagem de contêiner durante um deploy.

Por que nenhum erro de memória?

O Linux só mata um processo quando de fato esgota a memória que pode recuperar. Antes desse ponto, ele recupera memória do cache de páginas, as cópias de arquivos que mantém na RAM, incluindo o código de todo programa em execução.

Nos nossos servidores, a soma dos limites de memória dos contêineres chegava a cerca de 3,3 GB numa máquina com cerca de 1,8 GB utilizáveis. Normalmente eles não usam o limite todo ao mesmo tempo. Quando usavam, o kernel continuava despejando código de programas do cache para abrir espaço, e depois tinha de lê-lo de novo do disco no momento em que esse código voltava a rodar. Esse ciclo, o thrashing, pode deixar uma máquina quase totalmente sem resposta sem nunca esgotar tecnicamente a memória. Então nada é morto, e nada se recupera.

Sem swap, o kernel não tem onde colocar memória alocada mas raramente usada, então precisa tirá-la do cache.

A correção

O script de bootstrap dos servidores agora cria um arquivo de swap de 2 GB com um valor baixo de swappiness (10) toda vez que um servidor sobe ou é reparado. Swappiness baixo significa que o kernel ainda prefere manter a memória de trabalho na RAM, mas páginas pouco tocadas podem ir para o disco em vez de forçar o código dos programas para fora do cache. Aplicamos ao vivo nos dois servidores de produção e no de testes, e o pipeline de deploy republica o script de bootstrap a cada deploy de produção, para que um servidor substituído também receba a configuração.

A parte que mais nos preocupou: o servidor não saudável continuou no grupo

Nosso grupo de servidores usava health checks do EC2 ("a máquina está rodando?") e não health checks do balanceador de carga ("ela está respondendo requisições?"). Assim, um servidor que o balanceador já tinha descartado continuava saudável do ponto de vista do grupo. Ele nunca seria substituído. A produção ficaria discretamente rodando em um único servidor até alguém notar e reiniciar o outro.

Trocar o grupo para health checks do balanceador parece a correção óbvia, mas não é direto para nós: durante um deploy, os servidores respondem de propósito com erro no seu endpoint de saúde para que o balanceador os drene (veja como chegamos a zero 502s nos deploys). Um grupo que substitui servidores com base nesse sinal os substituiria no meio de cada deploy.

Por isso, por enquanto, acrescentamos uma etapa à nossa checklist de deploy: depois de cada deploy, verificar a saúde de cada destino no balanceador, e não só se o job de deploy passou. Se os comandos enviados a um servidor ficarem em "Pendente", ele está em thrashing: reinicie-o; ele já está fora de rotação.

O que tiramos disso

  • "Não travar" não é "saudável". O thrashing não produz erro, só uma lentidão tão extrema que a máquina para de responder.
  • Servidores pequenos precisam de swap. Mesmo pouco, com swappiness baixo, dá ao kernel um lugar para colocar memória fria.
  • Limites de memória que somam mais do que a máquina são uma aposta. Às vezes você perde. Saiba quando fez a aposta.
  • Saiba em qual health check o seu autoscaling confia. Um health check que só pergunta "a VM está ligada?" não substitui um servidor que parou de funcionar.

Mythex · Pricing · Crie qualquer coisa com IA · Templates de sites e apps · Mythex comparado · Glossário de criação de apps com IA · Ferramentas grátis para criar apps com IA · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)