Pular para conteúdo

Backups e a janela de restauração

O histórico de um alvo é uma cadeia: backups completos em um agendamento e, entre eles, um fluxo de alterações contínuo (WAL do Postgres, binlog do MySQL). Qualquer segundo coberto por um backup completo e pelas alterações seguintes pode ser restaurado. Esse intervalo é a janela point-in-time.

gantt
  dateFormat  YYYY-MM-DD HH:mm
  axisFormat  %a %d
  section Full backups
  daily full      :milestone, 2026-10-01 02:07, 0d
  daily full      :milestone, 2026-10-02 02:07, 0d
  daily full      :milestone, 2026-10-03 02:07, 0d
  daily full      :milestone, 2026-10-04 02:07, 0d
  section Change stream
  WAL / binlog segments :active, 2026-10-01 02:07, 2026-10-04 18:00

Backups completos

Engine Modo Ferramenta Restauração
Postgres 15–17 physical (padrão) pg_basebackup -Ft -X fetch pelo protocolo de replicação base backup + replay do WAL até o segundo
Postgres 15–17 logical pg_dump -Fc, um objeto por banco; exclusão de tabelas e exportações seletivas pg_restore, mais replay do WAL por uma cadeia física quando existir
MySQL 8.4 logical mysqldump --single-transaction --source-data=2 (routines, events, triggers) carga + replay do binlog até o segundo

Todo backup registra um inventário: bancos, tabelas, colunas, índices, estimativas de linhas e tamanhos, e a versão da migração quando existe uma tabela de migrações. É isso que o console e o tenax diff comparam.

O fluxo de alterações

Cada alvo com recuperação point-in-time tem um streamer:

  • Postgres: o receptor de WAL do próprio Tenax em um slot de replicação física (ADR 0005). O slot garante que nenhum WAL se perca enquanto o streamer reinicia.
  • MySQL: mysqlbinlog --read-from-remote-server --raw --stop-never a partir da posição do binlog do último completo.

Os segmentos são enviados à medida que terminam, e o segmento ainda em gravação é enviado a cada partialInterval (padrão 60 s), então o último minuto também pode ser restaurado. Cada segmento traz um resumo: commits, inserts, updates e deletes por tabela, DDL e, opcionalmente, prévias de linhas mascaradas.

Se o stream quebrar (um slot se perde, um binlog é expurgado), o Tenax marca a cadeia como quebrada, alerta (TenaxStreamChainBroken), inicia uma nova cadeia e faz um backup completo na hora (motivo chain-restart). A janela antiga continua restaurável até o ponto da quebra.

Retenção

Os backups completos são mantidos por camadas; os segmentos só até onde a janela precisa; a coleta de lixo remove todo o resto, nunca algo fixado.

Preset Janela Diário Semanal Mensal Anual
prod 7 dias 14 8 12 5
dev 3 dias 7 4 3 0
critical 14 dias 30 12 24 7

O primeiro completo confirmado de um dia é o diário desse dia; o de uma semana ISO, o semanal dela; e assim por diante. Um backup pode ter várias camadas; nada é copiado. Fixações (tenax pin <id> --reason …) retêm um backup independentemente das camadas. A GC grava o seu plano no bucket antes de excluir, exclui os manifestos antes dos dados e limpa uploads órfãos e incompletos depois de um dia.

Formato de armazenamento

<store prefix>/<org>/<project>/<namespace>/<target>/
  full/<backup-id>/manifest.json            # written last: the commit marker
  full/<backup-id>/data/<database>.zst.age  # dumps or the base backup tar
  full/<backup-id>/inventory.json.zst.age   # also readable with the catalog key
  full/<backup-id>/tags.json                # tiers, pins, verification results
  stream/…/<segment>.zst.age                # WAL / binlog segments and their summaries
  stream/position.json                      # the streamer's confirmed position
  • Compressão: zstd no nível da política, uma vez, antes da criptografia; ativada por padrão (ADR 0013). compression.algorithm: none armazena os dados como estão.
  • Criptografia: cada objeto é criptografado com age no cliente para os destinatários do store. O bucket nunca vê texto em claro.
  • Integridade: o tamanho e o SHA-256 de cada objeto estão no manifesto e são verificados em toda leitura.
  • Commit: um backup só existe depois que manifest.json é gravado. Uma falha antes disso deixa órfãos que a GC remove, nunca um backup que pareça completo.

Controle de carga

Os backups nunca disputam recursos às cegas com a produção: slots por host, por alvo e globais, um limite de banda, uma prioridade, um jitter nos agendamentos e uma proteção de carga que adia um backup completo enquanto o servidor tem conexões ativas demais, lag de replicação alto demais ou transações longas. Tudo isso é definido na BackupPolicy.