Migrações de Base de Dados Zero-Downtime Explicadas na Prática: O Padrão Expand-and-Contract

Migrações de Base de Dados Zero-Downtime Explicadas na Prática: O Padrão Expand-and-Contract

O Fim das Janelas de Manutenção às 03:00 da Manhã

Nos primórdios da web, alterar uma tabela na base de dados era um ritual nocturno. A equipa avisava os clientes de uma “janela de manutenção agendada” entre as duas e as quatro da manhã de domingo. A aplicação era desligada, colocava-se um ecrã de aviso, corria-se o script de migração e voltava-se a ligar tudo.

Em 2026, com plataformas SaaS a operar globalmente em diferentes fusos horários e lojas online a faturar 24 horas por dia, fechar um sistema para atualizar a base de dados é um erro operacional inaceitável. Não existem noites calmas quando tens clientes a usar o software em Lisboa, São Paulo ou Singapura. Deitar uma base de dados abaixo para mudar o nome de uma coluna quebra a confiança dos utilizadores e viola acordos de nível de serviço (SLA).

Ainda assim, muitas equipas continuam a causar paragens acidentais porque não entendem a forma como os motores relacionais gerem os bloqueios de tabelas durante alterações de estrutura.

O DESASTRE DO BLOQUEIO NUMA MIGRAÇÃO DIRETA

  • MIGRAÇÃO DIRETA: ALTER TABLE utilizadores RENAME COLUMN nome TO nome_completo;
  • Pede Bloqueio Exclusivo (AccessExclusiveLock - Bloqueia Leituras e Escritas!)
  • Uma Consulta SELECT Lenta em Curso Atrasa o Bloqueio
  • TODOS os Novos Pedidos Ficam Presos Atrás na Fila!
  • (Esgotamento Total da Pool de Conexões)
  • QUEDA DO SITE: HTTP 504 GATEWAY TIMEOUT

Na Webxtek, desenhamos plataformas preparadas para operar sem interrupções. Através do nosso serviço de alojamento gerido e apoio em consultoria técnica, mostramos às equipas como aplicar alterações complexas de esquemas enquanto o sistema processa milhares de pagamentos em simultâneo.


Como Funcionam os Bloqueios no PostgreSQL: O Perigo da Fila de Espera

Para fazeres migrações sem paragens, tens de conhecer a hierarquia de bloqueios do PostgreSQL.

Qualquer consulta SQL exige um nível de bloqueio na tabela. Enquanto várias leituras SELECT pedem apenas um AccessShareLock (que correm em paralelo sem qualquer atrito), comandos como ALTER TABLE ou DROP TABLE exigem um AccessExclusiveLock.

MATRIZ DE CONFLITOS DE BLOQUEIOS NO POSTGRESQL

  • TIPO DE BLOQUEIO CONFLITUA COM AccessShareLock AccessExclusiveLock: RowShareLock • RowExclusiveLock Share, Exclusive… • ShareLock • AccessExclusiveLock CONFLITUA COM TUDO!
  • DISPARADO POR Consultas SELECT normais: Exclusive, AccessExclusive SELECT FOR UPDATE • INSERT, UPDATE, DELETE • RowExclusive, Exclusive… Criação normal de índices • ALTER TABLE, DROP TABLE

O verdadeiro perigo está na fila de espera do PostgreSQL. Se o teu comando ALTER TABLE estiver à espera que uma consulta antiga termine para conseguir o bloqueio exclusivo, todos os novos pedidos SELECT e INSERT que chegarem depois dele ficam parados na fila atrás dele. Em escassos segundos, todas as ligações do servidor web esgotam-se e o teu site sai do ar.


O Padrão Expand-and-Contract: Quatro Fases sem Interrupções

O padrão Expand-and-Contract (ou padrão de expansão e contração) resolve este problema garantindo que a base de dados é sempre retrocompatível com a versão anterior do código durante todo o processo.

Imagina que queres mudar a coluna telefone para telefone_internacional:

A LINHA TEMPORAL DO PADRÃO EXPAND-AND-CONTRACT

  • FASE 1: EXPANSÃO (Migração na Base de Dados)
  • Crias a nova coluna telefone_internacional (permitindo nulos) ao lado da antiga.
  • A base de dados suporta agora ambos os campos em simultâneo.
  • FASE 2: ESCRITA DUPLA (Deploy da Aplicação v1.1)
  • A tua aplicação continua a ler de telefone, mas escreve nos dois campos ao mesmo tempo.
  • Todos os novos registos ficam sincronizados automaticamente.
  • FASE 3: BACKFILL ASSÍNCRONO (Script em Segundo Plano)
  • Um processo copia os registos históricos em pequenos lotes de 1.000 linhas de cada vez.
  • Zero bloqueios na tabela e zero lentidão para os clientes.
  • FASE 4: CONTRAÇÃO (Deploy da Aplicação v1.2 e Limpeza)
  • A aplicação passa a ler exclusivamente de telefone_internacional.
  • Numa última migração rápida, apagas a coluna antiga telefone.

Em nenhum momento deste ciclo o teu servidor fica bloqueado mais do que alguns milissegundos.


Passo a Passo Prático no Terminal e SQL

Aqui tens o guião prático para executares esta operação no teu servidor Debian:

Passo 1: Adicionar a Coluna com Limite de Espera

Define sempre um tempo limite de bloqueio (lock_timeout). Se o comando não conseguir o trinco em dois segundos, aborta imediatamente em vez de prender a fila de clientes:

-- Define limite máximo de espera para evitar prender conexões
SET lock_timeout = '2s';

-- Fase de Expansão: adiciona coluna permitindo valores nulos
ALTER TABLE utilizadores ADD COLUMN telefone_internacional VARCHAR(32);

Passo 2: Copiar Dados Antigos em Lotes (Backfill)

Nunca corras um UPDATE utilizadores SET telefone_internacional = telefone; direto numa tabela com milhões de linhas. Faz a migração em pequenos lotes com uma pausa ligeira:

#!/bin/bash
# Script de backfill seguro em lotes
TAMANHO_LOTE=2000
ULTIMO_ID=0

while true; do
  LINHAS=$(psql -d producao_db -t -A -c "
    WITH lote AS (
      SELECT id FROM utilizadores
      WHERE id > $ULTIMO_ID AND telefone_internacional IS NULL
      ORDER BY id ASC
      LIMIT $TAMANHO_LOTE
    )
    UPDATE utilizadores u
    SET telefone_internacional = telefone
    FROM lote
    WHERE u.id = lote.id
    RETURNING u.id;
  " | wc -l)

  echo "Atualizadas $LINHAS linhas..."
  if [ "$LINHAS" -eq 0 ]; then
    break
  fi
  sleep 0.2 # Dá descanso à base de dados para servir clientes
done

Passo 3: Criação de Índices sem Bloqueio

Ao criares índices na nova coluna, usa obrigatoriamente a opção CONCURRENTLY:

-- Cria o índice em segundo plano sem travar escritas
CREATE INDEX CONCURRENTLY idx_utilizadores_telefone ON utilizadores (telefone_internacional);

Podes consultar ferramentas abertas de validação de migrações no GitHub.


Soberania de Dados e Fiabilidade nos Teus Serviços

Quando desenvolvemos websites de alta performance, eliminar bloqueios de base de dados é indispensável para assegurar transações sub-milissegundo constantes.

Com a nossa consultoria técnica, ajudamos a tua equipa a dominar estes padrões avançados de engenharia, transformando as atualizações de software num processo invisível, seguro e totalmente contínuo.

Na prática, aplicas exatamente estes padrões operacionais em setores exigentes como saas empresarial b2b e especialistas em devops e arquitetura cloud. Quando alinhas a tua estrutura através de alojamento gerido para websites e aplicações e consultoria técnica antes de construir, transformas boas práticas técnicas numa vantagem competitiva real e mensurável para o teu negócio.

[+] [ INDEX_DIRECTORY ] 16 tópicos ▼
[ SYSTEM.FAQ ]

Perguntas Frequentes

Porque é que correr ALTER TABLE para mudar o nome de uma coluna deita abaixo a aplicação?

O comando ALTER TABLE exige um bloqueio exclusivo (AccessExclusiveLock). Todas as consultas SELECT e INSERT seguintes ficam presas na fila de espera até o bloqueio terminar, esgotando as ligações.

Quais são as quatro fases do padrão de migração Expand-and-Contract?

1. Expand (adiciona a coluna nova ao lado da antiga); 2. Dual-Write (a aplicação escreve em ambas); 3. Backfill (copia dados antigos em lotes); 4. Contract (muda as leituras e remove a coluna antiga).

Como deves adicionar uma coluna com valor obrigatório (NOT NULL) sem encravar a tabela?

Adicionas a coluna permitindo valores nulos, preenches os registos existentes em pequenos lotes em segundo plano, crias uma restrição CHECK com NOT VALID e só depois validas a restrição.

Porque deves usar sempre o parâmetro CONCURRENTLY ao criar índices em tabelas de produção?

A criação normal de índices bloqueia escritas na tabela (ShareLock). Com a opção CONCURRENTLY, o PostgreSQL percorre a tabela em duas passagens sem impedir operações de INSERT ou UPDATE.

> INICIAR_PROJETO

Precisa de um website que transmita confiança, apareça na pesquisa e dê mais força à sua presença digital? Comece a conversa aqui.