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: nonestocke 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.