Arquitetura real · Sênior
Stripe: migrações online em escala
Arquitetura real em produção. Pontos centrais: migração de dados online.
Resposta curta
Arquitetura real em produção. Pontos centrais: migração de dados online. O post de engenharia do Stripe descreve como a empresa migrou centenas de milhões de objetos de assinatura (Subscriptions) para um novo modelo de dados, mantendo o serviço no ar. O Stripe afirma fazer todas as atualizações de infraestrutura online, sem depender de janelas de manutenção planejadas.
01 · CONTEXTO
Por que migrar dados em produção é difícil
O post de engenharia do Stripe descreve como a empresa migrou centenas de milhões de objetos de assinatura (Subscriptions) para um novo modelo de dados, mantendo o serviço no ar. O Stripe afirma fazer todas as atualizações de infraestrutura online, sem depender de janelas de manutenção planejadas.
O post separa a dificuldade em três frentes. Na escala, se cada objeto levasse um segundo para migrar, a migração em sequência levaria mais de três anos para cem milhões de objetos. Na disponibilidade, o serviço de assinaturas não podia ser pausado. Na precisão, mudar milhares de linhas de uma vez quase certamente deixaria casos de borda passarem, e todo serviço precisava continuar contando com dados corretos.
02 · O MODELO ANTIGO
De uma assinatura por cliente a uma tabela própria
No começo, cada objeto Customer tinha no máximo uma assinatura, e as assinaturas ficavam guardadas junto dos clientes. Depois, alguns usuários quiseram clientes com várias assinaturas, e o campo único virou uma lista de assinaturas ativas.
Com o modelo inicial, o serviço lê e grava as assinaturas dentro do registro do cliente.
Com novas funcionalidades, qualquer mudança nas assinaturas atualiza o registro inteiro do cliente, e as consultas sobre assinaturas varrem objetos de clientes.
Esse modelo virou problema com o crescimento das funcionalidades: mudar as assinaturas de um cliente atualizava o registro inteiro dele, e consultas sobre assinaturas varriam objetos de clientes. A decisão foi guardar as assinaturas ativas separadamente, e o novo modelo move as assinaturas para uma tabela própria.
03 · ESCRITA DUPLA E BACKFILL
Duplicar as escritas e copiar o que já existe
A migração começa criando a nova tabela e passando a escrever nos dois lugares. No caso do Stripe, toda assinatura recém-criada era gravada nas tabelas Customers e Subscriptions. O post recomenda considerar o impacto dessa escrita extra no banco de produção e propõe mitigá-lo subindo aos poucos a porcentagem de objetos duplicados, enquanto se acompanham as métricas operacionais.
No modelo antigo, o serviço guarda as assinaturas dentro da tabela Customers.
A escrita dupla começa: cada assinatura recém-criada é gravada nas duas tabelas.
Para controlar o impacto no banco de produção, a porcentagem de objetos duplicados sobe aos poucos, com as métricas sob observação.
Os objetos antigos entram na nova tabela de forma preguiçosa, quando são atualizados.
Os objetos que já existiam eram copiados de forma preguiçosa: sempre que um deles era atualizado, passava automaticamente para a nova tabela. O que sobrasse era levado por um backfill final.
A parte mais cara do backfill em um banco no ar é apenas descobrir quais objetos precisam migrar, porque isso exigiria muitas consultas ao banco de produção e muito tempo. O Stripe tirou essa busca da produção: disponibilizou snapshots dos bancos ao cluster Hadoop e usou MapReduce para processar os dados de forma offline e distribuída.
Achar todas as assinaturas a migrar por consultas ao banco de produção seria a parte mais cara do backfill.
Os snapshots dos bancos ficam disponíveis ao cluster Hadoop, que processa os dados de forma offline e distribuída.
Um job Scalding produz a lista de IDs de assinaturas que precisam ser copiadas.
Uma frota de processos copia as assinaturas da lista em paralelo para a nova tabela.
Terminada a migração, o job roda de novo para confirmar que nenhuma assinatura existente ficou de fora da nova tabela.
04 · LEITURA, ESCRITA E REMOÇÃO
Trocar as leituras, inverter as escritas e aposentar o modelo antigo
Com as tabelas em sincronia, o passo seguinte é ler da nova. Para ter segurança de que os dados batem, o Stripe usou o Scientist, do GitHub: uma biblioteca Ruby que roda experimentos comparando dois caminhos de código e alerta se eles divergirem em produção. Se o caminho experimental gera um erro, o restante da aplicação não é afetado.
O experimento lia das duas tabelas e, se os resultados não coincidissem, levantava um erro para avisar os engenheiros da inconsistência. Depois de verificar que tudo batia, o Stripe passou a ler da nova tabela.
Antes da troca, todas as leituras de assinaturas usam a tabela Customers.
O experimento do Scientist lê das duas tabelas e compara os resultados.
Se os resultados não coincidem, um erro avisa os engenheiros da inconsistência.
Depois de verificar que tudo batia, as leituras passam a vir da tabela nova.
Nas escritas, a ordem se inverte: grava-se na tabela nova e depois arquiva-se na antiga.
Quando nenhum código depende do modelo antigo, deixa-se de escrever na tabela antiga e a nova vira a fonte da verdade.
O post considera as escritas possivelmente a parte mais desafiadora: a lógica de assinaturas (atualizações, rateios, renovações) se espalha por milhares de linhas em vários serviços. A chave foi o processo incremental, isolando os caminhos de código na menor unidade possível para aplicar cada mudança com cuidado, com as duas tabelas consistentes a cada passo.
Para garantir que nenhum código continuasse usando o array antigo, o post propõe lançar um erro quando a propriedade for chamada. Quando nada mais depende do campo antigo, deixa-se de escrever na tabela antiga, e a nova passa a ser a fonte da verdade. Os dados antigos saem de forma preguiçosa: o array é esvaziado a cada vez que uma assinatura é carregada, e um job e uma migração finais encontram o que sobrou.
05 · RESUMO
As quatro fases lado a lado e o que ajudou
| O que muda | Como o post reduz o risco | |
|---|---|---|
| Escrita dupla | Assinaturas recém-criadas vão para as duas tabelas | Sobe aos poucos a porcentagem de objetos duplicados, acompanhando as métricas operacionais |
| Leituras | As leituras passam para a tabela nova | O Scientist lê das duas tabelas e levanta um erro se os resultados não coincidem |
| Escritas | Grava-se na tabela nova e depois arquiva-se na antiga | As duas tabelas ficam consistentes a cada passo |
| Remoção | Deixa-se de escrever na tabela antiga e a nova vira a fonte da verdade | O array é esvaziado a cada carga e um job e uma migração finais encontram o que sobrou |
Perguntas frequentes
O que é Stripe: migrações online em escala?
Arquitetura real em produção. Pontos centrais: migração de dados online.
O que o design de Stripe: migrações online em escala cobre?
Ele está organizado nestas seções: Por que migrar dados em produção é difícil, De uma assinatura por cliente a uma tabela própria, Duplicar as escritas e copiar o que já existe, Trocar as leituras, inverter as escritas e aposentar o modelo antigo e As quatro fases lado a lado e o que ajudou.
Quanto tempo leva Stripe: migrações online em escala e qual é o nível?
Leva cerca de 17 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.