Aller au contenu

Les sauvegardes et la fenêtre de restauration

L'historique d'une cible est une chaîne : des sauvegardes complètes planifiées, et entre elles un flux de modifications continu (WAL Postgres, binlog MySQL). Toute seconde couverte par une sauvegarde complète et les modifications qui la suivent peut être restaurée. Cette plage est la fenêtre de restauration à un instant donné.

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

Sauvegardes complètes

Moteur Mode Outil Restauration
Postgres 15–17 physical (par défaut) pg_basebackup -Ft -X fetch via le protocole de réplication sauvegarde de base + rejeu du WAL à la seconde près
Postgres 15–17 logical pg_dump -Fc, un objet par base ; exclusions de tables et exports sélectifs pg_restore, plus rejeu du WAL via une chaîne physique s'il en existe une
MySQL 8.4 logical mysqldump --single-transaction --source-data=2 (routines, événements, triggers) chargement + rejeu du binlog à la seconde près

Chaque sauvegarde enregistre un inventaire : bases, tables, colonnes, index, estimations de lignes et tailles, ainsi que la version de migration quand une table de migrations existe. C'est ce que comparent la console et tenax diff.

Le flux de modifications

Chaque cible avec restauration à un instant donné a un streamer :

  • Postgres : le récepteur WAL propre à Tenax, sur un slot de réplication physique (ADR 0005). Le slot garantit qu'aucun WAL n'est perdu pendant un redémarrage du streamer.
  • MySQL : mysqlbinlog --read-from-remote-server --raw --stop-never à partir de la position binlog de la dernière sauvegarde complète.

Les segments sont envoyés dès qu'ils sont complets, et le segment en cours d'écriture est envoyé toutes les partialInterval (60 s par défaut) : la dernière minute est donc restaurable elle aussi. Chaque segment porte un résumé : commits, insertions, mises à jour et suppressions par table, DDL, et éventuellement des aperçus de lignes masqués.

Si le flux se rompt (un slot est perdu, un binlog est purgé), Tenax marque la chaîne comme rompue, alerte (TenaxStreamChainBroken), démarre une nouvelle chaîne et prend immédiatement une sauvegarde complète (raison chain-restart). L'ancienne fenêtre reste restaurable jusqu'à la rupture.

Rétention

Les sauvegardes complètes sont conservées par niveaux ; les segments ne sont gardés qu'aussi loin que la fenêtre l'exige ; le ramasse-miettes supprime tout le reste, jamais rien d'épinglé.

Préréglage Fenêtre Quotidien Hebdomadaire Mensuel Annuel
prod 7 jours 14 8 12 5
dev 3 jours 7 4 3 0
critical 14 jours 30 12 24 7

La première sauvegarde complète validée d'une journée est la quotidienne de ce jour ; celle d'une semaine ISO, son hebdomadaire ; et ainsi de suite. Une même sauvegarde peut porter plusieurs niveaux ; rien n'est copié. Les épingles (tenax pin <id> --reason …) conservent une sauvegarde quels que soient les niveaux. Le ramasse-miettes écrit son plan dans le bucket avant de supprimer, supprime les manifestes avant les données, et nettoie au bout d'un jour les envois orphelins et incomplets.

Format de stockage

<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
  • Compression : zstd au niveau défini par la politique, une seule fois, avant le chiffrement ; activée par défaut (ADR 0013). compression.algorithm: none stocke les données telles quelles.
  • Chiffrement : chaque objet est chiffré avec age côté client, vers les destinataires du store. Le bucket ne voit jamais de texte en clair.
  • Intégrité : la taille et le SHA-256 de chaque objet figurent dans le manifeste et sont vérifiés à chaque lecture.
  • Validation : une sauvegarde n'existe qu'une fois manifest.json écrit. Un crash avant cela laisse des orphelins que le ramasse-miettes supprime, jamais une sauvegarde qui a l'air complète.

Contrôle de charge

Les sauvegardes ne font jamais concurrence à l'aveugle à la production : des créneaux par hôte, par cible et globaux, une limite de bande passante, une priorité, une gigue sur les plannings, et une protection de charge qui reporte une sauvegarde complète tant que le serveur a trop de connexions actives, trop de retard de réplication ou des transactions longues. Tout cela se règle dans la BackupPolicy.