Conceitos
Migração online: dual write, backfill e troca de leitura
Intuição
Imagine trocar a fundação de uma loja sem nunca fechar as portas: você não derruba tudo de uma vez, constrói a fundação nova ao lado, passa a guardar as mercadorias novas nos dois lugares, leva as antigas aos poucos, confere se os dois estoques batem e só então passa a atender os clientes pelo novo. A loja continua vendendo o tempo todo, e o prédio antigo só é demolido quando ninguém mais depende dele. A ideia é trocar o lugar onde os dados moram em passos pequenos e verificáveis, em vez de em um único salto arriscado.
Como funciona
O padrão descrito pela Stripe tem quatro passos. No primeiro, a escrita dupla (dual write), toda nova escrita atualiza o armazenamento antigo e o novo; como a escrita extra pode pesar no banco de produção, a porcentagem de objetos duplicados é aumentada aos poucos, observando as métricas operacionais. A escrita dupla sozinha só cobre objetos novos, então um backfill copia os existentes: primeiro de forma preguiçosa (copiar quando o objeto é atualizado) e depois por uma cópia em massa, cuja lista de IDs pode ser gerada offline sobre snapshots do banco, para não sobrecarregar a produção com consultas; rodar de novo, ao final, o job que gera essa lista confirma que nada ficou faltando. No segundo passo, a troca de leitura, um experimento (no caso, a biblioteca Scientist) lê dos dois caminhos, compara os resultados e alerta quando divergem, sem afetar a aplicação se o caminho experimental falhar; só depois de tudo coincidir a leitura passa a vir do armazenamento novo. No terceiro, a ordem das escritas se inverte: grava-se primeiro no novo e depois no antigo, o que exige refatorar os caminhos de escrita; a Stripe o fez em pequenas unidades, com mudanças de poucas centenas de linhas por vez, e fez o acesso ao campo antigo lançar um erro grave para revelar qualquer uso esquecido. No quarto, quando nenhum código depende mais do dado antigo, para-se de escrever nele, ele é removido e o novo vira a fonte de verdade. Cada fase existe para reduzir um risco: a escrita dupla mantém os dois lados sincronizados, o backfill completa o histórico, a leitura comparada dá confiança antes de depender do novo, e a inversão e a limpeza só ocorrem com essa confiança. Migrar sem janela de indisponibilidade importa porque a Stripe faz suas atualizações de infraestrutura online, sem janelas de manutenção; e a escala pesa porque, se cada objeto levasse um segundo, copiar cem milhões deles em sequência levaria mais de três anos.
Na prática
Esse padrão serve quando é preciso mudar o modelo de dados de um serviço que não pode parar, como tirar uma lista de dentro de um registro para uma tabela própria, e há muitos pontos do código que usam o dado. O custo é conviver por um tempo com dois armazenamentos, escritas extras e código de transição, em troca de poder avançar, medir e perceber cedo qualquer divergência, antes de a leitura e a escrita dependerem do novo lado. Na prática, o artigo o usa para evitar uma janela de manutenção e uma troca única de milhares de linhas, em que casos de borda quase certamente passariam.
Use em um desenho
Pratique na escola de System Design os casos que dependem deste conceito.