Executando verificação de segurança...
7

Migrando um banco de dados PostgreSQL com 11 segundos de inatividade na AWS

Encontrei o aritgo How we migrated our PostgreSQL database with 11 seconds downtime onde o autor compartilha como foi realizar a migração de um banco de dados PostgreSQL de uma conta AWS para outra, usando o serviço de migração de banco de dados da Amazon.

Além disso, vi um comentário no Hacker News mencionando um outro processo de migração, que vou deixar ao final como bônus.

Migração com 11 segundos de inatividade, usando o AWS Database Migration Service (DMS)

O serviço GOV.UK Notify estava hospeado na GOV.UK Platform as a Service (PaaS), que foi aposentada, então houve uma migração de toda a infraestrutura para a AWS. A PaaS fornecia um banco de dados AWS RDS PostgreSQL para o serviço de notificações.

A equipe do serviço de notificações precisava configurar um novo banco de dados na própria conta AWS e fazer com que todos os aplicativos deles se comunicassem com o novo banco de dados. A parte difícil não era criar um novo banco de dados, mas sim transferir todos os dados e fazer com que os aplicativos usassem esse novo banco de dados, ao mesmo tempo em que tentavam ter um tempo de inatividade mínimo.

O banco de dados utilizava a versão 11 do PostgreSQL, com um tamanho de cerca de 400 GB, com 1,3 bilhão de linhas, 85 tabelas, 185 índices e 120 chaves estrangeiras, com algo em torno de 1.000 inserções ou atualizações por segundo.

1. Configuração da instância DMS

O DMS (AWS Database Migration Service) é o serviço de migração de bancos de dados fornecido pela Amazon.

O banco de dados de origem e o de destino estavam em diferentes contas AWS e residiam em diferentes nuvens privadas virtuais (VPCs), então eles configuraram de forma que o tráfego do DMS pudesse ser roteado diretamente de VPC para VPC, sem passar pela Internet pública.

O diagrama a seguri ilustra o processo de replicação do DMS, mas eu também trouxe em detalhes nos próximos tópicos quais foram os passos que o autor seguiu.

Diagrama de replicação do DMS. Do banco de dados de origem, para o endpoint de origem, para a tarefa de replicação, para o endpoint de destino, para o banco de dados de destino.
Fonte da imagem: AWS

2. Configuração do banco de dados de destino

O novo banco de dados foi criado na versão 15 do PostgreSQL. O esquema foi obtido usando pg_dump no banco original. Não aplicaram as chaves estrangeiras porque o DMS não tenta copiar os dados em uma ordem que respeita as chaves estrangeiras. Não criaram chaves primárias ou índices para não deixar o processo de carregamento mais lento, iram atualizar os índices depois da carga.

3. Carregamento total

Nessa etapa, o DMS copiou todos os dados. Ele não copia nenhum dado novo ou atualização recebida após esse ponto. Demorou cerca de 6 horas para a tarefa de carregamento total ser concluída. Após a conclusão, adicionaram os índices e restrições de chave, o que levou cerca de 3 horas.

4. Replicação

Para copiar as novas alterações do banco de origem, iniciaram a tarefa de replicação contínua do DMS, que lê todas as transações do log do banco de dados de origem que foram criadas após o início da tarefa de carregamento total e as envia para o banco de dados de destino. Esse processo levou algumas horas, então acompanharam a latência no processo de replicação do DMS para garantir que ele pudesse lidar com o número de alterações que aconteciam no banco de dados de origem e continuasse sincronizado.

Esse processo de replicação foi executado por cerca de 10 dias em segundo plano, esperando o momento em que os aplicativos parassem de se comunicar com o banco de dados de origem e começassem a se comunicar com o de destino. Já havia sido anunciado para os usuários um horário para a migração do tráfego.

5. Preparando para migrar o tráfego

O processo para migrar o tráfego dos aplicativos do banco de origem para o de destino foi o seguinte:

  1. Interromper todo o tráfego dos aplicativos para o banco de dados de origem. Nesse ponto, entrariam em um período de inatividade em que o Notify não estaria disponível.
  2. Certificar de que a replicação tenha sido atualizada para que todas as atualizações no banco de dados de origem tenham sido refletidas no banco de dados de destino.
  3. Permitir que os aplicativos comecem a se comunicar com o banco de dados de destino. Isso encerraria o tempo de inatividade.

Nessa fase, era importante não ter alguns aplicativos conversando com o banco de dados de origem e outros com o de destino. Se isso acontecesse, quaisquer alterações no banco de dados de destino não seriam refletidas no banco de dados de origem, o que significaria que os usuários obteriam dados inconsistentes.

Eles escreveram um script Python para esse processo para que pudesse ser explícito, facilmente repetível e muito mais rápido do que se feito manualmente. Quanto mais rápido isso fosse feito, menor seria o tempo de inatividade para os usuários do Notify. A meta era menos de 5 minutos de inatividade. Usaram esse script pelo menos 40 vezes durante testes e práticas anteriores.

A migração foi feita num sábado à noite, porque era um dos momentos mais tranquilos.

6. Parando o tráfego para o banco de dados de origem

O script interromperia todo o tráfego para o banco de dados de origem chamando pg_terminate_backend em todas as conexões dos aplicativos. Isso levou menos de um segundo. Também alteraram a senha do usuário PostgreSQL usado pelos aplicativos, o que significa que, se os aplicativos tentassem se reconectar ao banco de dados de origem, receberiam um erro de autenticação.

7. Verificando se a replicação foi atualizada

O script de migração verificava tabelas geradas pelo DMS para acompanhar o status da replicação, de forma a garantir que o banco de dados de destino estivesse totalmente atualziado.

Para garantir que todas as alterações fossem replicadas, depois que os aplicativos parassem de se comunicar com o banco de dados de origem, o script de migração gravaria um único registro no banco de dados de origem e esperaria para ver se ele chegaria com segurança ao banco de dados de destino.

8. Fazendo uma troca suave de tráfego

Para que os aplicativos se conectassem ao banco de dados, eles precisariam saber a localização do banco de dados e também um nome de usuário e senha. Essas informações eram fornecidas aos aplicativos em uma variável de ambiente no seguinte formato:

SQLALCHEMY_DATABASE_URI=postgresql://original-username:[email protected]1.rds.amazonaws.com:5432

A reimplantação dos aplicativos, para a troca da variável de ambiente entrar em efeito levaria cerca de 5 minutos. Para minimizar o tempo de inatividade, eles fizeram duas alterações antes da migração para que pudessem usar uma mudança rápida no DNS ao invés de reimplantar os aplicativos.

A primeira mudança foi criar um usuário no banco de dados de origem e de destino que tivesse o mesmo nome de usuário e senha.

A segunda mudança foi criar um registro DNS no AWS Route53 para database.notifications.service.gov.uk com um TTL (time to live) de 1 segundo, com duas ponderações:

  1. 100% dos resultados de DNS ponderados para o local do banco de dados de origem.
  2. 0% dos resultados de DNS ponderados para o local do banco de dados de destino.

Então, definiram o URI usado pelos aplicativos para usar o novo nome de usuário e senha e para usar o novo nome de domínio para a localização do banco de dados.

SQLALCHEMY_DATABASE_URI=postgresql://shared-username:[email protected]:5432

Dessa forma, quando quisessem trocar o banco de dados para o qual os aplicativos apontassem, o script de migração só precisaria atualizar a ponderação do DNS na AWS para 100% dos resultados sendo enviados para o local do banco de dados de destino e esperar 1 segundo para o TTL expirar. Então, da próxima vez que os aplicativos tentassem consultar o banco de dados, eles estariam consultando o banco de dados de destino.

Migração feita

O artigo menciona que tiveram aproximadamente 11 segundos de inatividade. Essa migração teve uma complexidade maior por conta dos aplicativos que se conectavam ao banco de dados, mas achei a solução mencionada na etapa 8 bem interessante.

Apesar disso, parece que eles experimentariam outra opção no lugar do DMS numa próxima oportunidade:

Optamos por usar DMS porque era bem suportado pela GOV.UK PaaS e também podíamos obter suporte da AWS. Se estivéssemos fazendo uma migração de banco de dados PostgreSQL para PostgreSQL no futuro, investiríamos mais tempo tentando ferramentas alternativas, como o pglogical. O DMS potencialmente adicionou mais complexidade e um processo de replicação desconhecido do que poderíamos ter encontrado com outras ferramentas. Isso confirma o que a própria AWS diz sobre migrações de PostgreSQL para PostgreSQL.

Migração com 20 segundos de inatividade, usando o Amazon RDS Blue-Green Deployments

O Ozzie_osman comentou como usou o Amazon RDS Blue-Green Deployments para atualizar um banco de dados Postgres da versão 13 para a 15.

Existem dois deploys: o "Azul" e o "Verde". O seu deploy "Azul" continuará servindo o tráfego, e a AWS utilizará replicação lógica para manter o deploy "Verde" sincronizado. Você pode modificar ou testar o deploy "Verde", contanto que não faça nenhuma escrita nele, porque as escritas devem ir para a configuração que está no ar, que é a Azul, e serão replicadas para a Verde.

Quando você estiver pronto, pode realizar a troca, então a AWS irá realizar alguns processos: verificará se os ambients Azul e Verde estão sincronizados, interromperá as conexões e escritas, esperará alguns segundos para garantir que a replicação esteja atualizada, renomeará seu banco de dados, e então permitirá as conexões e escritas novamente.

Diagrama de como funciona a sincronização entre os ambientes Azul e Verde.
Fonte da imagem: AWS.

Para o Ozzie_osman, houve menos de 20 segundos de inatividade durante esse processo.

Tivemos menos de 20 segundos de inatividade, pelas nossas contas. E tivemos uma réplica primária e várias réplicas de leitura e a AWS alterou com sucesso a configuração completa sem problemas. Você nem precisa mudar sua configuração porque a AWS troca os URLs do banco de dados para você. O verde torna-se azul, o azul torna-se azul antigo e, quando estiver pronto, você exclui o "azul antigo".

2

Eu acho muito massa o Write-Ahead Logging do PostgreSQL. Eu particularmente uso para fazer backups em tempo real, economizando bastante storage.

1