Vai al contenuto

I backup e la finestra di ripristino

La storia di un target è una catena: backup completi pianificati e, tra l'uno e l'altro, un flusso di modifiche continuo (WAL di Postgres, binlog di MySQL). Qualsiasi secondo coperto da un backup completo e dalle modifiche successive può essere ripristinato. Questo intervallo è la finestra 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

Backup completi

Engine Modalità Tool Ripristino
Postgres 15–17 physical (predefinita) pg_basebackup -Ft -X fetch tramite il protocollo di replica backup di base + replay del WAL al secondo
Postgres 15–17 logical pg_dump -Fc, un oggetto per database; esclusione di tabelle ed esportazioni selettive pg_restore, più replay del WAL tramite una catena fisica se esiste
MySQL 8.4 logical mysqldump --single-transaction --source-data=2 (routine, eventi, trigger) caricamento + replay del binlog al secondo

Ogni backup registra un inventario: database, tabelle, colonne, indici, stime delle righe e dimensioni, e la versione delle migrazioni quando esiste una tabella delle migrazioni. È ciò che la console e tenax diff confrontano.

Il flusso di modifiche

Ogni target con point-in-time recovery ha uno streamer:

  • Postgres: il receiver WAL di Tenax su uno slot di replica fisica (ADR 0005). Lo slot garantisce che nessun WAL vada perso mentre lo streamer si riavvia.
  • MySQL: mysqlbinlog --read-from-remote-server --raw --stop-never dalla posizione del binlog dell'ultimo backup completo.

I segmenti vengono caricati man mano che si completano, e il segmento ancora in scrittura viene caricato ogni partialInterval (predefinito 60 s), così è ripristinabile anche l'ultimo minuto. Ogni segmento porta un riepilogo: commit, insert, update e delete per tabella, DDL e, facoltativamente, anteprime mascherate delle righe.

Se il flusso si interrompe (uno slot viene perso, un binlog viene eliminato), Tenax marca la catena come interrotta, genera un alert (TenaxStreamChainBroken), avvia una nuova catena ed esegue subito un backup completo (motivo chain-restart). La vecchia finestra resta ripristinabile fino al punto di interruzione.

Conservazione

I backup completi vengono conservati per livelli; i segmenti vengono conservati solo fin dove serve alla finestra; la garbage collection rimuove tutto il resto, ma mai ciò che è bloccato.

Preset Finestra Giornalieri Settimanali Mensili Annuali
prod 7 giorni 14 8 12 5
dev 3 giorni 7 4 3 0
critical 14 giorni 30 12 24 7

Il primo backup completo confermato di un giorno è il giornaliero di quel giorno; di una settimana ISO il suo settimanale; e così via. Un backup può appartenere a più livelli; non viene copiato nulla. I blocchi (tenax pin <id> --reason …) trattengono un backup indipendentemente dai livelli. La GC scrive il suo piano nel bucket prima di eliminare, elimina i manifest prima dei dati e ripulisce gli upload orfani e incompleti dopo un giorno.

Formato di archiviazione

<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
  • Compressione: zstd al livello della policy, una sola volta, prima della cifratura; attiva per impostazione predefinita (ADR 0013). compression.algorithm: none salva i dati così come sono.
  • Cifratura: ogni oggetto viene cifrato con age lato client verso i destinatari dello store. Il bucket non vede mai dati in chiaro.
  • Integrità: dimensione e SHA-256 di ogni oggetto sono nel manifest e vengono verificati a ogni lettura.
  • Commit: un backup esiste solo quando manifest.json è stato scritto. Un crash prima di quel momento lascia oggetti orfani che la GC rimuove, mai un backup che sembra completo.

Controllo del carico

I backup non competono mai alla cieca con la produzione: slot per host, per target e globali, un limite di banda, una priorità, un jitter sulle pianificazioni e una protezione dal carico che rinvia un backup completo finché il server ha troppe connessioni attive, troppo ritardo di replica o transazioni di lunga durata. Tutto si imposta nella BackupPolicy.