Incidente · Sênior
GitHub 2012: failover promove réplica atrasada
Incidente real. Pontos centrais: Algoritmos de Consenso, Padrões de Disponibilidade e Padrões de Consistência.
Resposta curta
Incidente real. Pontos centrais: Algoritmos de Consenso, Padrões de Disponibilidade e Padrões de Consistência. O post de disponibilidade que o GitHub publicou em setembro de 2012 é a fonte deste caso. Ele descreve duas quedas no início da mesma semana e aponta o failover automático do banco de produção principal como a causa raiz das duas.
01 · CONTEXTO
Um cluster novo que troca de primário sozinho
O post de disponibilidade que o GitHub publicou em setembro de 2012 é a fonte deste caso. Ele descreve duas quedas no início da mesma semana e aponta o failover automático do banco de produção principal como a causa raiz das duas.
Em meados de agosto, a operação substituiu um par de servidores MySQL baseados em DRBD por um cluster de três nós. O cluster apresenta à aplicação dois IPs virtuais, um de leitura e escrita e outro somente leitura, gerenciados por Pacemaker e Heartbeat. O Percona Replication Manager coordena a replicação e move entre os nós os papéis de ativo (o mestre que aceita leitura e escrita) e de standby (réplica somente leitura).
Segundo o post, o novo desenho dava failovers mais eficientes. Na arquitetura anterior, trocar de banco exigia a partida a frio do MySQL; no cluster novo o MySQL roda em todos os nós o tempo todo, e o failover apenas move o IP virtual depois de descarregar as transações e ajustar a variável read_only.
A aplicação fala com o banco pelo IP virtual de leitura e escrita, que aponta para o nó em papel ativo.
O nó standby é uma réplica somente leitura do nó ativo.
O gerenciador do cluster faz os health checks e move o IP virtual e os papéis entre os nós.
Como o MySQL já roda em todos os nós, o failover se resume a mover o IP virtual, sem partida a frio.
02 · SEGUNDA-FEIRA
Dois failovers que ninguém queria
A origem foi uma migração de banco que gerou mais carga do que a operação já tinha visto nesse tipo de migração. A carga foi tanta que os health checks do Percona Replication Manager falharam no mestre.
Em resposta, o gerenciador moveu o papel ativo para outro servidor do cluster e parou o MySQL no nó que julgou falho. O banco escolhido tinha o buffer pool do InnoDB frio e teve desempenho ruim; a carga de consultas do site sobre esse cache frio logo fez os health checks falharem de novo, e o papel ativo voltou ao servidor de origem.
Com a carga da migração, os health checks do gerenciador falham no nó ativo.
O gerenciador move o papel ativo para outro servidor e para o MySQL no nó que julgou falho.
O nó escolhido tem o buffer pool do InnoDB frio e responde mal à carga de consultas do site.
Os health checks falham de novo e o papel ativo volta ao servidor em que estava.
O autor do post liga o maintenance-mode, em que o gerenciador não faz health checks nem failover automático.
O desempenho do site se recuperou aos poucos, conforme o buffer pool atingiu níveis normais.
03 · TERÇA-FEIRA
A partição e a eleição do nó atrasado
Na manhã seguinte, um desenvolvedor avisou a operação de resultados de consulta incorretos vindos do nó em papel de standby. A investigação concluiu que o maintenance-mode do dia anterior tinha impedido ações que fariam o nó eleito standby trocar de mestre de replicação e começar a replicar.
Ao tentar desativar o maintenance-mode, ocorreu um segfault do Pacemaker que resultou em uma partição do estado do cluster. Dois nós, chamados a e b, rejeitavam a maior parte das mensagens do terceiro, c, enquanto c rejeitava a maior parte das mensagens dos outros dois.
No primeiro cluster, a eleição foi interrompida por mensagens do segundo e o MySQL foi parado. No segundo, de um único nó, o nó c foi eleito e as mensagens posteriores do cluster de dois nós foram descartadas. O nó c era justamente o que a operação já havia determinado estar desatualizado.
A equipe detectou o problema e desligou o nó desatualizado, para encerrar a partição e evitar mais divergência de dados. Com isso, todo o acesso ao banco de produção, e portanto ao github.com, ficou fora do ar.
Os três nós trocam mensagens de cluster, e o cluster exige acordo da maioria antes de agir.
Um segfault do Pacemaker particiona o cluster: a e b rejeitam a maior parte das mensagens de c, e c rejeita as deles.
No cluster de a e b, a eleição de mestre é interrompida por mensagens do outro lado e o MySQL é parado.
No cluster de um nó só, c é eleito, e c era o nó que a operação já havia determinado estar desatualizado.
A equipe desliga o nó desatualizado para encerrar a partição, e todo o acesso ao banco de produção cai.
04 · O ESTRAGO
Dados fora de sincronia entre armazenamentos
A divergência de dados tornou possíveis inconsistências entre o MySQL e outros armazenamentos. O GitHub usa Redis para consultar entradas do feed do painel e rotas de repositório a partir de ids gerados automaticamente pelo MySQL; para registros criados na janela, as relações entre os dois armazenamentos saíram de sincronia.
| Efeito descrito pela fonte | Contexto | |
|---|---|---|
| Painéis | Alguns eventos criados na janela apareceram nos painéis de usuários errados | O Redis é consultado com ids gerados pelo MySQL |
| Roteamento | Alguns repositórios criados na janela foram roteados incorretamente | As relações entre os armazenamentos saíram de sincronia |
| Repositórios privados | Dezesseis repositórios privados ficaram acessíveis a quem não era colaborador ou da equipe | Por sete minutos, segundo o post |
05 · A DECISÃO
Failover só quando a operação manda
O post afirma que, se alguém da operação fosse consultado sobre se o failover deveria ter ocorrido, a resposta seria um não categórico. Ele ressalva que há muitas situações em que o failover automático é uma ótima estratégia de disponibilidade, mas conclui que a disponibilidade do banco primário de produção não é uma delas.
Por isso, a configuração do Pacemaker foi alterada para que o failover do papel ativo só ocorra quando iniciado por um membro da operação. A empresa também investiga formas de que failovers inevitáveis não prejudiquem o desempenho, incluindo mecanismos para aquecer o buffer pool dos bancos escravos, e faz uma auditoria da pilha Pacemaker e Heartbeat.
O failover do papel ativo passa a depender de um membro da operação, e o gerenciador não o inicia sozinho.
Para failovers inevitáveis, a empresa investiga formas de aquecer o buffer pool dos bancos escravos.
A pilha Pacemaker e Heartbeat passa por uma auditoria focada no caminho de código que disparou o segfault.
Perguntas frequentes
O que é GitHub 2012: failover promove réplica atrasada?
Incidente real. Pontos centrais: Algoritmos de Consenso, Padrões de Disponibilidade e Padrões de Consistência.
O que o design de GitHub 2012: failover promove réplica atrasada cobre?
Ele está organizado nestas seções: Um cluster novo que troca de primário sozinho, Dois failovers que ninguém queria, A partição e a eleição do nó atrasado, Dados fora de sincronia entre armazenamentos e Failover só quando a operação manda.
Quanto tempo leva GitHub 2012: failover promove réplica atrasada e qual é o nível?
Leva cerca de 14 minutos para ler e tem nível Sênior.
Agora projete você mesmo
Rode este caso como uma entrevista na escola de System Design: você toma as decisões, o tutor as questiona e você vê a nota do seu desenho.