Sobre a interrupção de 6 de dezembro: medidas e soluções
Em 6 de dezembro, aconteceu aquilo que sempre mais tememos. Às 13:23, notamos problemas de capacidade na nossa plataforma. Logo ficou claro que era um problema sério, que resultou em indisponibilidade para muitos casos de uso. Lamentamos profundamente ter permitido que isso acontecesse. Disponibilidade e confiabilidade são essenciais para o serviço que oferecemos aos nossos clientes, por isso trabalhamos duro para que interrupções como essa sejam as mais raras possíveis.

Mas, em vez de apenas pedir desculpas, queremos mostrar os bastidores e explicar exatamente o que fizemos para corrigir o problema o mais rápido possível.
Vamos a uma análise detalhada (post-mortem) dos acontecimentos.
Cronologia dos eventos:
13:12 - Fizemos o deploy dos preparativos para migrar para uma infraestrutura baseada em VPC. Isso incluía novas variáveis de ambiente com configurações — como as sub-redes, os grupos de segurança e os load balancers aos quais adicionar máquinas — específicas da nova VPC que estamos criando para cada região. Além disso, incluía mudanças no GoInstance — uma ferramenta que escrevemos em Go para gerenciar a inicialização e a ativação de máquinas, e também a remoção delas. A mudança não representava a migração para VPC em si; apenas preparava o terreno, mantendo a compatibilidade com a nossa configuração atual sem VPC. Migrar para VPC nos permite melhorar a segurança e aproveitar recursos da AWS exclusivos de VPC, como tipos de instância com desempenho maior a um custo menor. A mudança foi testada a fundo, tanto localmente quanto no CI, mas, como as variáveis de ambiente em produção são diferentes das de desenvolvimento e staging, uma incompatibilidade conseguiu passar despercebida.
13:23 - Chegou o primeiro alerta do pager, indicando que estávamos rodando com menos instâncias de upload do que deveríamos. O problema passou despercebido por um tempo porque carregar um novo ambiente exige novos processos, e o nosso deploy blue/green levou um tempo para substituir todos os processos ativos.
13:26 - Equipe de Resposta a Emergências (Emergency Response Team, ERT) acionada.
13:32 - Constatou-se que não conseguíamos iniciar novas máquinas por causa de variáveis de ambiente inválidas (incompatibilidade nos AMI-IDs e nos nomes dos Security Groups). Em alguns casos, o GoInstance fazia referência a valores inexistentes.
13:39 - À medida que as máquinas antigas eram retiradas do rodízio ou ficavam inacessíveis, passamos a rodar com uma única máquina por região, que os autoscalers se recusavam a retirar.
13:40 - A ERT corrigiu a incompatibilidade e iniciou um build.
13:45 - Twitter e statuspage atualizados.
13:49 - O build foi implantado.
13:51 - Por causa de um bug não relacionado na forma como o GoInstance é compilado, descobrimos que as mudanças não tinham entrado em produção.
13:55 - Intrigada com isso, a equipe tentou reverter completamente o build com problema.
14:01 - Por causa do mesmo bug, a reversão também não ativou as mudanças. Como descobrimos depois, se tivéssemos revertido para um ponto mais antigo, teria funcionado. Explicando: há alguns meses, quando migramos o nosso stack para Nix, introduzimos um bug que só recompilava o GoInstance se as mudanças nele viessem junto com mudanças em outras partes do nosso stack. Quando tentamos corrigir o GoInstance, as mudanças não foram detectadas nem implantadas em produção. A ERT levou algum tempo para descobrir isso.
14:08 - A ERT corrigiu o problema mencionado na nossa configuração do Nix, e voltamos a conseguir implantar mudanças. Iniciamos outro build e fizemos o deploy.
14:17 - As frotas da UE e dos EUA voltaram à capacidade desejada. Recentemente, uma parte grande do stack tinha sido adicionada, mas ainda não estava nas nossas AMIs, o que deixou a inicialização das máquinas mais lenta do que estamos acostumados.
14:34 - Todos os serviços foram verificados como restabelecidos, todas as conversas com clientes relacionadas foram resolvidas, e atualizamos o Twitter e o statuspage.
Que medidas tomamos?
-
Novas AMIs foram criadas para todas as regiões e tipos de máquina, fazendo com que o tempo de inicialização das nossas máquinas volte a ficar perto de três minutos
-
O bug na nossa configuração do Nix foi corrigido, para que as mudanças no GoInstance sempre sejam refletidas no nosso build
-
A incompatibilidade no nosso ambiente foi corrigida
Juntas, essas medidas fizeram tudo voltar a funcionar normalmente. Sabemos, porém, que daqui para frente precisaremos de medidas adicionais para garantir que algo assim nunca mais aconteça.
Que outras medidas vamos tomar?
Como parte do nosso deploy, os autoscalers iniciam máquinas, o que deveria ter interrompido o deploy antes que ele causasse danos. Infelizmente, descobrimos que, por causa de um problema não relacionado, esse teste prévio foi executado no ambiente anterior, e não no que estava sendo implantado. Vamos corrigir isso para que, daqui para frente, esse teste funcione de forma confiável e consiga detectar problemas como este.
Outras partes da nossa suíte de testes automatizados também poderiam ter detectado o ambiente inválido, mas não o verificavam porque o ambiente de staging é diferente do ambiente de produção. Estamos investigando se conseguimos deixar nossos ambientes mais parecidos.
Pedimos desculpas
Mais uma vez, lamentamos muito pelo transtorno que causamos. Esperamos que este post-mortem tenha esclarecido o que exatamente causou a interrupção e o que estamos fazendo para garantir que isso nunca mais aconteça. Se você foi afetado por essa interrupção, entre em contato com a nossa equipe de suporte, e vamos tentar resolver a situação da melhor forma!
