1. Início
  2. Blog
  3. Modernização de legado
Modernização de legado

Migração de banco de dados sem parar o produto

Como migrar um banco de dados com o produto no ar: sincronização, verificação, virada em etapas e rollback, de quem liderou a migração de uma plataforma em uso.

Illustration of data blocks flowing between two database cylinders, with an orange cutover switch marking a live database migration
Nesta página · 7 seções
  1. O que é uma migração de banco de dados?
  2. Por que mover dados é a parte mais difícil de substituir um sistema em produção?
  3. Quais são as principais estratégias: big bang, trickle e dual write?
  4. Como manter o banco antigo e o novo sincronizados?
  5. Como verificar os dados antes da virada?
  6. Como fazer rollback se algo der errado?
  7. Planejando uma migração?

Principais pontos

  • Trate os dados como a parte mais arriscada de qualquer substituição de sistema, não como uma tarefa para o final.
  • Escolha a estratégia (big bang, trickle ou dual write) com base em quanto downtime e risco o negócio consegue tolerar.
  • Mantenha o sistema antigo e o novo sincronizados, com uma única fonte da verdade clara a todo momento.
  • Verifique com comparações automatizadas, não clicando pela aplicação.
  • Defina o plano de rollback antes da virada, e teste esse plano.

Uma migração de banco de dados é o processo de mover dados de um banco para outro, ou de um schema para outro, para que uma aplicação passe a rodar no novo. Em um produto em produção, a parte difícil não é copiar linhas. É fazer isso enquanto os usuários continuam lendo e escrevendo, sem perder, duplicar ou corromper nada.

A abordagem que funciona na prática: copiar os dados em segundo plano, manter os dois bancos sincronizados por um tempo, comparar os dois, migrar as leituras e depois as escritas em pequenos passos, e manter um caminho de volta para o sistema antigo até confiar no novo. O resto deste artigo passa por cada etapa.

O que é uma migração de banco de dados?

O termo cobre vários trabalhos diferentes, e misturar um com o outro gera confusão:

  • Migração de schema: alterar tabelas, colunas ou índices dentro do mesmo banco.
  • Migração de engine: trocar um produto de banco de dados por outro, como de uma engine SQL para outra diferente, ou de um banco de documentos para um relacional.
  • Migração de hospedagem: levar a mesma engine para um novo servidor ou provedor de nuvem.
  • Migração de modelo: remodelar os dados para se adequarem a um novo desenho da aplicação, muitas vezes durante uma reescrita ou um replatforming.

As migrações de engine e de modelo são as arriscadas. Elas mudam a forma dos dados ou como eles são armazenados, e a aplicação precisa continuar funcionando durante a mudança. Tudo o que vem a seguir se aplica principalmente a esses casos. Uma limpeza de código pura é outro trabalho, mais próximo de refatoração sem mudar comportamento.

Por que mover dados é a parte mais difícil de substituir um sistema em produção?

Código pode ser publicado, testado e revertido em minutos. Dados, não. Depois que um usuário grava um registro no banco novo, você não pode simplesmente fazer deploy da versão antiga e fingir que nada aconteceu.

Alguns motivos pelos quais isso fica difícil rápido:

  • Os dados não param de mudar. Qualquer cópia que você faz já está desatualizada quando termina.
  • Dados antigos são bagunçados. Sistemas legados acumulam nulls, duplicados, formatos inconsistentes e regras que vivem só no código da aplicação, não no schema.
  • Ninguém lembra das regras. Uma coluna chamada status pode ter significado três coisas diferentes ao longo dos anos.
  • Os erros são silenciosos. Uma conversão de fuso horário errada ou um campo truncado não lança erro. Aparece semanas depois na reclamação de um cliente.
  • Os fluxos de dinheiro dependem disso. Pedidos, pagamentos, assinaturas e saldos precisam ser exatos.

Na avanzzada, liderei a migração completa de uma plataforma que se candidata automaticamente a vagas de emprego pelos seus usuários, levando toda a arquitetura de uma stack legada para uma nova enquanto as pessoas continuavam usando o produto todos os dias. Parar o produto não era uma opção, então cada passo precisava ser reversível. A lição que tirei desse tipo de trabalho: você planeja primeiro a movimentação dos dados, e o plano do código vem a partir dela.

Quais são as principais estratégias: big bang, trickle e dual write?

Existem três padrões comuns. A maioria das migrações reais combina os três.

EstratégiaComo funcionaPrincipal benefícioPrincipal risco
Big bangParar as escritas, copiar tudo, virar, reiniciarSimples de entenderO downtime cresce com o volume de dados; difícil de desfazer
Trickle (em fases)Mover os dados em lotes, por tabela, tenant ou grupo de usuáriosRaio de impacto pequenoDois sistemas no ar por muito tempo
Dual writeA aplicação escreve nos dois bancos ao mesmo tempoO banco novo fica sempre atualizadoAs escritas podem divergir se uma delas falhar

Big bang

Funciona para volumes pequenos de dados, ferramentas internas ou produtos em que uma janela de manutenção é aceitável. É a estratégia mais fácil de entender, mas, se a verificação falhar depois da virada, você fica sob pressão com os usuários esperando.

Trickle

Você migra por fatias: um segmento de clientes, uma funcionalidade, uma família de tabelas. Cada fatia é verificada antes da próxima. Isso combina bem com migração incremental, em que uma camada de roteamento manda parte do tráfego para o sistema novo e o resto para o antigo. Em uma migração com o produto no ar, colocar esse roteamento na frente de tudo é a primeira coisa que eu faço, antes de escrever qualquer código novo. Rodar dois sistemas lado a lado tem um custo, mas, na minha experiência, uma reescrita big-bang geralmente custa mais e demora mais, porque o sistema antigo precisa continuar rodando em paralelo de qualquer forma enquanto o novo o alcança.

Dual write

A aplicação grava cada alteração nos dois bancos. Parece simples e não é. Se a primeira escrita dá certo e a segunda falha, os bancos ficam divergentes, e não existe uma transação que abranja os dois. Uso dual write com cuidado, com o banco antigo como fonte da verdade e com jobs de reconciliação que pegam divergências. Muitos times preferem replicação ou change data capture, que explico a seguir.

Como manter o banco antigo e o novo sincronizados?

A regra que sigo: a qualquer momento, exatamente um banco é a fonte da verdade para um determinado dado. O outro acompanha.

Formas comuns de manter o seguidor atualizado:

  1. Cópia inicial em massa mais atualização incremental. Tire um snapshot, carregue no banco novo e depois reaplique as mudanças que aconteceram desde o snapshot.
  2. Change data capture (CDC). Leia o log de alterações do banco antigo e aplique essas alterações no novo. Isso evita mexer no código da aplicação, e muitas engines de banco e ferramentas suportam isso de alguma forma.
  3. Dual write no nível da aplicação. Útil quando o formato dos dados muda muito, mas precisa de reconciliação.
  4. Sincronização periódica em lote. Aceitável para dados que mudam pouco, como tabelas de referência.

Concentre a transformação em um só lugar

Se o schema novo é diferente do antigo, coloque a lógica de mapeamento em um único módulo ou pipeline bem testado. Quando a mesma transformação é reimplementada em um script de backfill, em um job de sincronização e na aplicação, as três versões acabam divergindo.

Torne as operações idempotentes

Jobs de sincronização falham e rodam de novo. Se aplicar a mesma alteração duas vezes cria duplicados, uma hora você vai ter duplicados. Use IDs estáveis e upserts para que rodar de novo não cause problema.

Mova as escritas depois das leituras

Uma ordem segura é: sincronizar os dados, mudar as leituras para o banco novo para um grupo pequeno de usuários, observar, ampliar o grupo e só então mover as escritas. Feature flags são a ferramenta usual para isso, porque permitem mudar o roteamento sem um deploy.

Como verificar os dados antes da virada?

Não confie só na contagem de linhas. As contagens batem mesmo quando os dados estão errados de formas que importam. Faça verificações em camadas:

  • Contagem de linhas por tabela como uma primeira verificação, barata.
  • Checksums ou hashes sobre as colunas-chave, comparados entre o antigo e o novo.
  • Agregados sobre valores de negócio: valor total de pedidos por dia, assinaturas ativas por plano, saldos por conta.
  • Comparação de registros por amostragem: escolha registros aleatórios, mais casos extremos como o mais antigo, o maior e os que têm nulls ou caracteres incomuns.
  • Verificações de integridade referencial: chaves estrangeiras órfãs, registros pai ausentes, valores únicos duplicados.

Compare comportamento, não só dados

Uma técnica forte é a leitura em sombra (shadow reading). A aplicação lê dos dois bancos para a mesma requisição, devolve ao usuário o resultado do antigo e registra qualquer diferença. As divergências mostram as regras que ninguém documentou antes que seus usuários as encontrem.

Verifique com mais rigor os fluxos de dinheiro

Comece por tudo que envolve pagamentos, pedidos ou saldos. Quando assumo um sistema, os fluxos de dinheiro vêm logo depois de conseguir acesso e fazer o build funcionar, e uma migração merece a mesma prioridade. Reconcilie esses dados com uma fonte externa, como os registros do seu provedor de pagamentos, e não só com o banco antigo, porque o banco antigo pode já conter erros.

Defina antes o que é "bom o suficiente"

Combine qual taxa de divergência bloqueia a virada. Para dados financeiros, é zero diferença sem explicação. Para dados de baixo risco, você pode aceitar exceções conhecidas e documentadas.

Como fazer rollback se algo der errado?

O rollback é onde muitos planos de migração ficam vagos. Rollback de código é fácil. Rollback de dados só é possível se você projetou para isso.

Regras práticas:

  • Mantenha o banco antigo intacto e rodando depois da virada, por um período definido. Não desative no dia da virada.
  • Continue sincronizando no sentido inverso quando puder. Depois que as escritas forem para o banco novo, replique as alterações de volta para o antigo, para que voltar não perca dados recentes. É trabalho extra, e vale a pena em sistemas críticos.
  • Vire em etapas, para que um problema afete um grupo pequeno e o rollback seja só mudar uma flag para esse grupo.
  • Faça backups verificados antes de cada passo importante, e teste se consegue restaurá-los. Um backup não testado é uma esperança, não um plano.
  • Deixe o gatilho por escrito. Decida com antecedência quais sinais significam "fazer rollback": taxas de erro, contagem de divergências, pagamentos com falha, chamados de suporte.

Seja honesto sobre os limites. Depois de tempo suficiente no banco novo, reverter pode ser mais difícil do que corrigir para frente. Defina explicitamente o ponto sem volta, e só chegue nele depois que a verificação estiver limpa por tempo suficiente para você confiar.

Planejando uma migração?

Se você está prestes a mover um banco de dados em produção e quer uma segunda opinião, mande um email para me@filipeeduardo.dev com uma breve descrição do seu cenário. Fico feliz em dizer o que eu verificaria primeiro, como um engenheiro trocando ideias com outro.

Perguntas frequentes

Quanto tempo leva uma migração de banco de dados?

Depende do volume de dados, de quão diferentes são os schemas e de quanta verificação o negócio precisa. A cópia costuma ser a parte mais curta. Limpar os dados, construir a sincronização e verificar geralmente tomam a maior parte do tempo. Eu não confiaria em quem dá uma data fechada antes de olhar os dados.

Dá para migrar um banco de dados com zero downtime?

Muitas vezes com muito pouco, usando sincronização mais uma virada em etapas. Eu não prometeria zero literalmente. Às vezes um congelamento de escritas curto e planejado no passo final é mais seguro do que um esquema complexo para evitá-lo.

Devo mudar o schema e mover os dados ao mesmo tempo?

Sempre que possível, não. Ir para uma nova engine e redesenhar o modelo em um único passo multiplica as formas de algo quebrar. Mova os dados fielmente primeiro e depois remodele, ou o contrário, mas separe os riscos.

Qual é o erro mais comum?

Tratar a migração como um evento de uma noite e pular a verificação e o planejamento de rollback. O segundo mais comum é não ter uma única fonte da verdade durante o período de sincronização, o que leva a divergências silenciosas.

database migration

Filipe Eduardo

Engenheiro de Software Sênior. Sete anos construindo produtos web e mobile de ponta a ponta e liderando os times que os entregam.

Acompanhe

Quer conversar
sobre isso?

Trabalho com problemas assim todos os dias. Me conte o seu.

Fale comigo