Papers
Chaos Engineering
Ali Basiri, Niosha Behnam, Ruud de Rooij, Lorin Hochstein, Luke Kosewski, Justin Reynolds, Casey Rosenthal · IEEE Software 33(3):35-41 (maio-junho de 2016), 2016
O problema: deixar o sistema em paz não é opção
Os autores, da equipe de Traffic and Chaos do Netflix, começam lembrando uma máxima de Jim Gray: para melhorar a disponibilidade, instale software e hardware já comprovados e depois deixe-os em paz. Para empresas que prestam serviços pela Internet, isso não funciona, porque elas precisam mudar o tempo todo para adicionar funcionalidades e melhorar desempenho. No Netflix, engenheiros publicam código novo e alteram parâmetros de configuração em produção centenas de vezes por dia, e mesmo assim a disponibilidade importa: um cliente que não consegue assistir a um vídeo por causa de uma queda pode deixar de ser cliente. A resposta histórica da empresa foi o Chaos Monkey, serviço interno que escolhe aleatoriamente instâncias de máquinas virtuais de produção e as encerra, só em horário comercial, para que os engenheiros possam reagir rápido. O objetivo era forçar o projeto de serviços que sobrevivam à perda de instâncias individuais. Funcionou: hoje todos os engenheiros projetam serviços assumindo essa falha. Depois vieram os exercícios Chaos Kong, que simulam a falha de uma região inteira da Amazon EC2, e o Failure Injection Testing (FIT), que faz requisições entre serviços falharem para verificar degradação graciosa. O paper define então Chaos Engineering como a disciplina de experimentar em um sistema distribuído para ganhar confiança na sua capacidade de resistir a condições turbulentas em produção, de uma falha de hardware a um valor malformado num parâmetro de configuração.
A mudança para a perspectiva de sistema
O núcleo da proposta é tratar um conjunto de serviços em produção como um único sistema e entendê-lo injetando entradas do mundo real, como falhas transitórias de rede, picos de requisições ou dados malformados, e observando o que acontece na fronteira do sistema. A abordagem tradicional usa uma especificação funcional: dado um programa f, entradas x produzem saídas y = f(x), e se o sistema tem vários programas, a especificação também define cada um deles. Os autores argumentam que, em sistemas distribuídos reais, essa especificação é incompleta. A escala e a complexidade do comportamento dos usuários e da infraestrutura tornam difícil enumerar todas as entradas, e compor as especificações de cada serviço para raciocinar sobre o todo é impraticável. Pela perspectiva de sistema, o engenheiro parte do pressuposto de que o software já foi implantado, tem usuários ativos, e observa métricas na fronteira do sistema, interessando-se pelo comportamento típico dessas métricas ao longo do tempo, o chamado comportamento em regime estável (steady state). Esse comportamento pode ser alterado por interações de usuários, por mudanças feitas pelos engenheiros (configuração, código) e por eventos como a falha transitória de um serviço de terceiros. As perguntas passam a ser 'tudo parece funcionar?' e 'os usuários estão reclamando?', em vez de 'a implementação bate com a especificação?'.
Princípio 1: uma hipótese sobre o regime estável e a métrica SPS
Um experimento exige especificar hipóteses, variáveis independentes, variáveis dependentes e contexto. Os autores destilam quatro princípios: construir uma hipótese em torno do regime estável, variar eventos do mundo real, executar experimentos em produção e automatizar para rodarem continuamente. Para o primeiro, 'funciona direito' é vago demais, então o atributo de qualidade escolhido é a disponibilidade. O Netflix usa fallbacks para degradação graciosa: se o cache na frente de um serviço B falha, o serviço A pode consultar B diretamente, o que aumenta latência e carga mas não afeta o usuário no curto prazo. Se o serviço de bookmarks falha, a interface simplesmente começa os vídeos do início. A pergunta que importa é se os usuários conseguem encontrar e assistir a algum conteúdo, e isso é operacionalizado pela métrica SPS (stream starts per second), quantas reproduções começam a cada segundo. O SPS varia de forma lenta e previsível ao longo do dia, o que reflete a premissa de que sistemas complexos têm comportamento regular o bastante para ser previsto. As hipóteses focam em métricas visíveis na fronteira do sistema, como SPS, e não em métricas finas como carga de CPU ou tempo de consulta ao banco, que servem apenas para checar se o sistema está de fato saudável durante o experimento e podem encerrar o teste mais cedo. Um exemplo de hipótese: a troca de uma região para outra terá impacto mínimo no SPS.
Princípio 2: variar eventos do mundo real
O caminho feliz (happy path) é a execução em que nenhuma entrada leva a erros ou casos de canto, e a tentação ao testar o próprio código é concentrar-se nele. No mundo real, porém, clientes enviam requisições malformadas, serviços dependentes enviam respostas malformadas, servidores morrem, discos enchem, a memória se esgota, a latência de rede dispara por ordens de grandeza e o tráfego sobe sem aviso. O paper cita um estudo segundo o qual 92% das falhas catastróficas de sistemas resultaram de tratamento incorreto de erros não fatais. Daí o segundo princípio: ao desenhar experimentos, amostrar o espaço de entradas que podem ocorrer de verdade. Uma fonte óbvia são os dados históricos de quedas anteriores, razão adicional para fazer post-mortems; mas qualquer entrada que possa perturbar o regime estável é candidata. Exemplos usados no Netflix: encerrar instâncias de VM, injetar latência entre serviços, fazer requisições entre serviços falharem, derrubar um serviço interno e tornar uma região inteira da Amazon indisponível. Às vezes o evento é simulado em vez de injetado: o Netflix não tira uma região da Amazon do ar, e sim age como se ela tivesse caído, redirecionando requisições. Em outros casos o evento é aplicado só a um subconjunto de usuários, como estratégia de mitigação de risco. Cabe ao engenheiro equilibrar o realismo do evento e o risco de dano ao sistema.
Princípios 3 e 4: rodar em produção e automatizar
Nenhum servidor individual tem poder de computação, memória, armazenamento, banda ou confiabilidade para hospedar o Netflix, então o serviço precisa ser um sistema distribuído, e os autores esperam que, com a popularidade dos microsserviços, cada vez mais engenheiros construam sistemas assim. Testes tradicionais não bastam para achar suas falhas. Dois exemplos observados no Netflix: um servidor sobrecarregado demora cada vez mais a responder e um cliente enfileira requisições de saída numa fila local sem limite, que consome memória até o cliente falhar; ou um serviço atrás de um cache devolve um erro transitório que é cacheado por engano, e outros clientes recebem esse erro. São modos de falha que exigem teste de integração, e em alguns contextos isso só é possível em produção, pois o Netflix não consegue reproduzir toda a arquitetura para um teste ponta a ponta. Mesmo quando seria possível, nunca se reproduz tudo: clientes sintéticos se comportam diferente dos reais, e há problemas como configuração de DNS. O quarto princípio vem do fato de o sistema mudar continuamente (comportamento de serviços, novos serviços, parâmetros, metadados do catálogo), o que corrói a confiança em resultados antigos. Um experimento começa manual, mas precisa ser automatizado; a cadência depende do contexto. No Netflix, o Chaos Monkey roda continuamente em dias úteis e os exercícios Chaos Kong ocorrem uma vez por mês.
Como rodar um experimento e o futuro da disciplina
O paper resume um experimento em quatro passos. Primeiro, definir o regime estável como alguma saída mensurável que indique comportamento normal. Segundo, formular a hipótese de que ele se mantém tanto no grupo de controle quanto no grupo experimental. Terceiro, introduzir variáveis que reflitam eventos reais, como servidores que caem, discos que falham ou conexões de rede cortadas. Quarto, tentar refutar a hipótese procurando diferença de regime estável entre os dois grupos. O exemplo hipotético é o serviço de bookmarks, útil mas não crítico: usa-se o SPS como saída, escolhe-se uma pequena porcentagem dos usuários e divide-se em controle e experimental; para o grupo experimental, falham-se seletivamente todas as requisições ao serviço de bookmarks associadas a esses usuários, via o serviço de injeção de falhas (FIT); espera-se SPS aproximadamente igual nos dois grupos. Ao fim, ou há mais confiança na capacidade do sistema de manter seu comportamento, ou uma fraqueza foi revelada e indica um caminho de melhoria. Sobre o futuro, os autores dizem que os conceitos não são fundamentalmente novos, mas a prática ainda está na infância, e listam frentes abertas: estudos de caso de outros domínios, adoção organizacional, ferramentas reutilizáveis (as do Netflix são internas e acopladas à sua infraestrutura) e modelos de injeção de eventos, já que muitas falhas decorrem de combinações de eventos e não de eventos isolados.
Veja as ideias em ação
Pratique na escola de System Design os desenhos que usam este paper.