Como um limite de conexões do banco de dados quase reiniciou os Macs dos meus clientes
Mantemos uma pequena frota de Mac minis para clientes. Um daemon em um hub consulta cada máquina por SSH, envia telemetria para um plano de controle e escala quando uma máquina fica em silêncio. Primeiro ele espera. Depois corta e religa a energia da máquina por uma tomada inteligente. Depois chama uma pessoa.
Semana passada, o plano de controle começou a responder com 500. Treze minutos depois, o daemon tinha concluído que os quatro Macs estavam mortos e registrado um corte de energia para cada um. Dois eram de clientes pagantes. Um terceiro tinha sido vendido naquela manhã.
O que falhou de verdade
Um pool de conexões do banco de dados. O plano de controle roda em funções serverless ligadas a um pooler Postgres com limite de quinze conexões para o projeto inteiro. Algumas funções aquecidas usaram todas, e toda rota da API que dependia do banco começou a falhar. Os detalhes estão em um post separado.
Os Macs estavam bem. O SSH funcionava. Todas as sessões gráficas estavam no ar. O cliente que fazia um build em um deles não percebeu nada. A única coisa quebrada era o sistema cujo trabalho era saber se os Macs estavam quebrados.
Como uma frota saudável pareceu morta
O daemon guardava um horário por máquina: a última vez em que uma consulta deu certo. A lógica de escalonamento comparava esse horário com o agora. A consulta, com razão, começava buscando a lista de máquinas no plano de controle, e terminava antes da hora quando essa busca falhava.
Então, durante a pane, nenhuma consulta rodou, nenhum horário avançou e todos os intervalos cresceram juntos. A lógica de escalonamento não sabia que o daemon nem tinha tentado. Ela viu treze minutos de silêncio vindo de quatro máquinas e fez o que foi feita para fazer.
ladder: Unit 02 unreachable 12m51s → power cycle ladder: Unit 03 unreachable 12m51s → power cycle ladder: Unit 04 unreachable 12m51s → power cycle ladder: Unit 05 unreachable 12m43s → power cycle
Por que nada reiniciou
Nenhuma tomada inteligente estava configurada. O passo de corte de energia procurou uma tomada, não achou e seguiu em frente. Depois, as quatro máquinas mostravam uptimes de seis dias, seis dias, um dia e cerca de uma hora. Nada tinha sido tocado.
Isso é sorte, não projeto. As tomadas inteligentes fazem parte do plano para o próximo lote de máquinas. Se já estivessem instaladas, um problema de conexão com o banco de dados teria cortado a energia de três Macs de clientes. Um deles talvez estivesse no meio de um build. Nenhum deles tinha feito nada de errado.
A solução
Agora o daemon registra quando conseguiu, pela última vez, buscar a lista de unidades e de fato tentar as máquinas. A lógica de escalonamento se recusa a agir se isso não aconteceu há pouco tempo, e registra o motivo: a falha está no plano de controle, não nas unidades.
ladder: skipped, no successful unit poll in 14m02s (control plane, not the units)
Essa linha diz exatamente o que ela se recusa a fazer e por quê. É o que a antiga deveria ter dito logo na primeira vez.
A regra por baixo disso é simples. Uma remediação precisa exigir prova de que a verificação rodou. "Tentamos alcançar e falhamos" é prova. "Não tivemos notícias" não é, porque também é assim que uma pane de quem escuta se parece.
O que testar na sua própria automação
Tínhamos testado o que acontece quando um Mac morre. Nunca tínhamos testado o que acontece quando morre a coisa que vigia os Macs. Esses não são o mesmo teste, e o segundo é o que estica a mão até o botão de energia.
Perguntas
- Ações de recuperação como cortar a energia devem ser automáticas?
- Sim, mas só com prova concreta de que o próprio alvo falhou. Uma ação que dispara pela falta de informação vai disparar em qualquer pane do sistema que coleta essa informação.
- Como testar isso sem quebrar a produção?
- Derrube o observador, não os nós. Impeça o daemon de alcançar o plano de controle e veja o que a remediação decide. Se ela escalar, está tirando conclusões do silêncio.
- Qual é o limite certo para considerar algo inacessível?
- Mais longo do que qualquer instabilidade esperada do plano de controle. E a contagem só deve começar depois de uma tentativa falha de alcançar o nó, nunca a partir da última vez em que o nó por acaso foi visto.
Faça suas próprias contas na calculadora ou alugue um runner.