Backups und das Wiederherstellungsfenster¶
Die Historie eines Ziels ist eine Kette: Vollsicherungen nach Zeitplan und dazwischen ein fortlaufender Änderungsstrom (Postgres-WAL, MySQL-Binlog). Jede Sekunde, die von einer Vollsicherung und den darauf folgenden Änderungen abgedeckt ist, lässt sich wiederherstellen. Diese Spanne ist das Point-in-Time-Fenster.
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
Vollsicherungen¶
| Engine | Modus | Werkzeug | Wiederherstellung |
|---|---|---|---|
| Postgres 15–17 | physical (Standard) |
pg_basebackup -Ft -X fetch über das Replikationsprotokoll |
Base-Backup + WAL-Replay auf die Sekunde |
| Postgres 15–17 | logical |
pg_dump -Fc, ein Objekt pro Datenbank; Tabellenausschlüsse und selektive Exporte |
pg_restore, plus WAL-Replay über eine physische Kette, falls vorhanden |
| MySQL 8.4 | logical |
mysqldump --single-transaction --source-data=2 (Routinen, Events, Trigger) |
Laden + Binlog-Replay auf die Sekunde |
Jedes Backup erfasst ein Inventar: Datenbanken, Tabellen, Spalten, Indizes, Zeilenschätzungen und Größen sowie
die Migrationsversion, wenn eine Migrationstabelle existiert. Genau das vergleichen die Konsole und tenax diff.
Der Änderungsstrom¶
Jedes Ziel mit Point-in-Time-Recovery hat einen Streamer:
- Postgres: der eigene WAL-Receiver von Tenax auf einem physischen Replikations-Slot (ADR 0005). Der Slot garantiert, dass kein WAL verloren geht, während der Streamer neu startet.
- MySQL:
mysqlbinlog --read-from-remote-server --raw --stop-neverab der Binlog-Position der letzten Vollsicherung.
Segmente werden hochgeladen, sobald sie vollständig sind, und das gerade geschriebene Segment wird alle
partialInterval (Standard 60 s) hochgeladen, sodass auch die letzte Minute wiederherstellbar ist. Jedes Segment
trägt eine Zusammenfassung: Commits, Inserts, Updates und Deletes pro Tabelle, DDL und optional maskierte
Zeilenvorschauen.
Reißt der Stream ab (ein Slot geht verloren, ein Binlog wird gelöscht), markiert Tenax die Kette als unterbrochen,
alarmiert (TenaxStreamChainBroken), beginnt eine neue Kette und erstellt sofort eine Vollsicherung (Grund
chain-restart). Das alte Fenster bleibt bis zum Abbruch wiederherstellbar.
Aufbewahrung¶
Vollsicherungen werden nach Stufen aufbewahrt; Segmente nur so weit zurück, wie das Fenster sie braucht; die Garbage Collection entfernt alles andere, nie aber etwas Angeheftetes.
| Preset | Fenster | Täglich | Wöchentlich | Monatlich | Jährlich |
|---|---|---|---|---|---|
prod |
7 Tage | 14 | 8 | 12 | 5 |
dev |
3 Tage | 7 | 4 | 3 | 0 |
critical |
14 Tage | 30 | 12 | 24 | 7 |
Die erste abgeschlossene Vollsicherung eines Tages ist dessen Tagessicherung, die einer ISO-Woche deren
Wochensicherung, und so weiter. Ein Backup kann mehrere Stufen tragen; nichts wird kopiert. Pins
(tenax pin <id> --reason …) halten ein Backup unabhängig von den Stufen. Die GC schreibt ihren Plan in den
Bucket, bevor sie löscht, löscht Manifeste vor den Daten und räumt verwaiste und unvollständige Uploads nach einem
Tag auf.
Speicherformat¶
<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
- Komprimierung: zstd auf der Stufe der Policy, einmal, vor der Verschlüsselung; standardmäßig aktiv
(ADR 0013).
compression.algorithm: nonespeichert die Daten unverändert. - Verschlüsselung: Jedes Objekt wird auf dem Client mit age für die Empfänger des Stores verschlüsselt. Der Bucket sieht nie Klartext.
- Integrität: Größe und SHA-256 jedes Objekts stehen im Manifest und werden bei jedem Lesen geprüft.
- Commit: Ein Backup existiert erst, wenn
manifest.jsongeschrieben ist. Ein Absturz davor hinterlässt Waisen, die die GC entfernt, nie ein Backup, das vollständig aussieht.
Laststeuerung¶
Backups konkurrieren nie blind mit der Produktion: Slots pro Host, pro Ziel und global, ein Bandbreitenlimit, eine
Priorität, ein Jitter auf Zeitplänen und ein Lastschutz, der eine Vollsicherung verschiebt, solange der Server
zu viele aktive Verbindungen, zu viel Replikationsverzögerung oder lang laufende Transaktionen hat. All das wird in
der BackupPolicy eingestellt.