Przejdź do treści

Kopie zapasowe i okno przywracania

Historia celu to łańcuch: pełne kopie zapasowe według harmonogramu, a między nimi ciągły strumień zmian (WAL w Postgres, binlog w MySQL). Można przywrócić każdą sekundę objętą pełną kopią zapasową i następującymi po niej zmianami. Ten zakres to okno 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

Pełne kopie zapasowe

Silnik Tryb Narzędzie Przywracanie
Postgres 15–17 physical (domyślnie) pg_basebackup -Ft -X fetch przez protokół replikacji kopia bazowa + odtwarzanie WAL co do sekundy
Postgres 15–17 logical pg_dump -Fc, jeden obiekt na bazę danych; wykluczanie tabel i selektywne eksporty pg_restore, plus odtwarzanie WAL przez łańcuch fizyczny, jeśli istnieje
MySQL 8.4 logical mysqldump --single-transaction --source-data=2 (procedury, zdarzenia, wyzwalacze) wczytanie + odtwarzanie binlogu co do sekundy

Każda kopia zapasowa zapisuje inwentarz: bazy danych, tabele, kolumny, indeksy, szacunkową liczbę wierszy i rozmiary, a także wersję migracji, jeśli istnieje tabela migracji. To właśnie porównują konsola i tenax diff.

Strumień zmian

Każdy cel z odtwarzaniem point-in-time ma jeden streamer:

  • Postgres: własny odbiornik WAL Tenax na fizycznym slocie replikacji (ADR 0005). Slot gwarantuje, że żaden WAL nie zostanie utracony podczas restartu streamera.
  • MySQL: mysqlbinlog --read-from-remote-server --raw --stop-never od pozycji binlogu ostatniej pełnej kopii.

Segmenty są wysyłane, gdy się zakończą, a segment wciąż zapisywany jest wysyłany co partialInterval (domyślnie 60 s), więc ostatnią minutę również można przywrócić. Każdy segment zawiera podsumowanie: commity, wstawienia, aktualizacje i usunięcia na tabelę, DDL oraz opcjonalnie zamaskowane podglądy wierszy.

Jeśli strumień się przerwie (slot zostanie utracony, binlog wyczyszczony), Tenax oznacza łańcuch jako przerwany, wysyła alert (TenaxStreamChainBroken), rozpoczyna nowy łańcuch i od razu wykonuje pełną kopię zapasową (powód chain-restart). Stare okno pozostaje możliwe do przywrócenia aż do miejsca przerwania.

Retencja

Pełne kopie zapasowe są przechowywane według poziomów; segmenty tylko tak daleko wstecz, jak wymaga tego okno; odśmiecanie usuwa wszystko inne, nigdy nic przypiętego.

Preset Okno Dzienne Tygodniowe Miesięczne Roczne
prod 7 dni 14 8 12 5
dev 3 dni 7 4 3 0
critical 14 dni 30 12 24 7

Pierwsza zatwierdzona pełna kopia danego dnia jest kopią dzienną tego dnia; tygodnia ISO jej kopią tygodniową; i tak dalej. Jedna kopia zapasowa może mieć kilka poziomów; nic nie jest kopiowane. Przypięcia (tenax pin <id> --reason …) zatrzymują kopię zapasową niezależnie od poziomów. GC zapisuje swój plan w buckecie, zanim cokolwiek usunie, usuwa manifesty przed danymi i po jednym dniu sprząta osierocone i niekompletne uploady.

Format przechowywania

<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
  • Kompresja: zstd na poziomie z polityki, jednokrotnie, przed szyfrowaniem; domyślnie włączona (ADR 0013). compression.algorithm: none zapisuje dane bez zmian.
  • Szyfrowanie: każdy obiekt jest szyfrowany przez age po stronie klienta dla odbiorców magazynu. Bucket nigdy nie widzi tekstu jawnego.
  • Integralność: rozmiar i SHA-256 każdego obiektu są w manifeście i weryfikowane przy każdym odczycie.
  • Zatwierdzenie: kopia zapasowa istnieje dopiero wtedy, gdy zostanie zapisany manifest.json. Awaria wcześniej zostawia osierocone obiekty, które usuwa GC, nigdy kopię, która wygląda na kompletną.

Kontrola obciążenia

Kopie zapasowe nigdy nie konkurują na ślepo z produkcją: sloty na host, na cel i globalne, limit przepustowości, priorytet, losowe przesunięcie harmonogramów i ochrona obciążenia, która odkłada pełną kopię zapasową, gdy serwer ma zbyt wiele aktywnych połączeń, zbyt duże opóźnienie replikacji lub długotrwałe transakcje. Wszystko to ustawia się w BackupPolicy.