Blog JSystems - uwalniamy wiedzę!

Szukaj

PostgreSQL

Point-in-time recovery - jak odtworzyć bazę do konkretnej chwili

W skrócie

  • Ktoś skasował dane albo zrobił zły UPDATE i chcemy cofnąć bazę do stanu sprzed tej operacji, a nie tylko do ostatniego pełnego backupu.
  • Sam backup bazowy pokazuje stan z chwili jego wykonania - do odtworzenia dowolnej minuty potrzebujemy jeszcze archiwum plików WAL, które opisują każdą zmianę.
  • Robimy odtworzenie kopii bazowej, wskazujemy PostgreSQL katalog z archiwum WAL i podajemy docelowy moment w czasie w pliku konfiguracyjnym - serwer sam odtworzy zmiany do wybranej chwili.

Point-in-time recovery (PITR, odtwarzanie do punktu w czasie) to funkcja, która ratuje bazę wtedy, gdy zwykły backup to za mało. Pokazujemy, jak przygotować archiwizację WAL i jak cofnąć klaster dokładnie do sekundy sprzed feralnej operacji.

Jak to wygląda w praktyce

Sytuacja jest zawsze podobna. O 14:32 ktoś uruchomił na produkcji DELETE FROM zamowienia bez klauzuli WHERE albo migracja usunęła kolumnę, której nie powinna. Zauważamy to pół godziny później. Mamy nocny backup bazowy z 02:00, ale przywrócenie go oznacza utratę całego dnia pracy. Chcielibyśmy stanu z 14:31:59 - minutę przed katastrofą. Zwykłe przywrócenie kopii bazowej tego nie da, bo ta kopia zna tylko stan z 02:00. Cała reszta dnia jest zapisana w plikach WAL (write-ahead log, dziennik zmian) i to z nich odtwarzamy brakujące godziny.

Dlaczego tak się dzieje

PostgreSQL każdą zmianę danych zapisuje najpierw do dziennika WAL, a dopiero potem trafia ona do właściwych plików tabel. Ten dziennik to strumień, który opisuje historię bazy krok po kroku. Kopia bazowa (wykonana przez pg_basebackup) to zamrożony obraz plików z jednej chwili. Jeśli chcemy odtworzyć bazę do dowolnego późniejszego momentu, musimy wziąć ten obraz i dograć do niego kolejne wpisy z WAL aż do wybranego punktu. Warunek jest jeden: pliki WAL z okresu od backupu do awarii muszą być bezpiecznie zarchiwizowane. Domyślnie PostgreSQL po pewnym czasie kasuje stare segmenty WAL, więc bez wcześniej włączonej archiwizacji ciągłej PITR jest niemożliwy - nie da się go włączyć wstecz.

Jak to rozwiązać krok po kroku

  1. Wcześniej, na sprawnej bazie, włączamy archiwizację WAL. W postgresql.conf ustawiamy wal_level = replica (domyślne), archive_mode = on oraz archive_command, na przykład kopiujące segment do bezpiecznego katalogu: archive_command = 'test ! -f /archiwum/wal/%f && cp %p /archiwum/wal/%f'. Restartujemy klaster.
  2. Regularnie wykonujemy kopię bazową: pg_basebackup -D /backup/baza -Fp -Xs -P. To ona jest punktem startowym każdego odtworzenia.
  3. Gdy przychodzi awaria, zatrzymujemy uszkodzony klaster i odkładamy jego katalog danych na bok (nie kasujemy - może się przydać). Rozpakowujemy świeżą kopię bazową do pustego katalogu danych.
  4. W katalogu danych tworzymy pusty plik-sygnał recovery.signal. Jego obecność mówi PostgreSQL, że po starcie ma wejść w tryb odtwarzania, a nie normalnie wstać.
  5. W postgresql.conf ustawiamy restore_command = 'cp /archiwum/wal/%f %p' (skąd brać archiwalne segmenty) oraz cel odtwarzania: recovery_target_time = '2026-09-28 14:31:59'. Zamiast czasu możemy podać recovery_target_xid (numer transakcji) albo recovery_target_name, jeśli wcześniej oznaczyliśmy punkt przez pg_create_restore_point.
  6. Startujemy klaster. PostgreSQL odtworzy kopię bazową, a potem będzie stosował kolejne wpisy WAL aż do wskazanego momentu, po czym zatrzyma odtwarzanie i wystawi bazę tylko do odczytu.
  7. Sprawdzamy, czy dane są w oczekiwanym stanie. Jeśli tak, promujemy bazę do trybu zapisu poleceniem SELECT pg_wal_replay_resume() lub ustawiając recovery_target_action = 'promote' przed startem. Domyślnie serwer po osiągnięciu celu pauzuje, żebyśmy zdążyli sprawdzić dane.

Jak sprawdzić, że zadziałało

Po starcie w logu klastra zobaczymy wpisy typu recovery stopping before commit of transaction oraz last completed transaction was at log time 2026-09-28 14:31:.... To potwierdza, do jakiej chwili doszło odtwarzanie. Następnie łączymy się psql i sprawdzamy dane - odpytujemy usuniętą tabelę i liczymy wiersze, których miało brakować. Stan odtwarzania podejrzymy zapytaniem SELECT pg_is_in_recovery(): dopóki zwraca true, baza jest w trybie odtwarzania (tylko odczyt). Po promocji zwróci false. Dobrze jest też wykonać świeżą kopię bazową odtworzonego klastra, bo po PITR linia czasu WAL się zmienia i stare archiwum nie jest już w pełni spójne z nową bazą.

Wróć do listy: 100 najczęstszych pytań i problemów z PostgreSQL

Szkolenie Administracja, replikacja i tuning baz danych PostgreSQL

Sprawdź szkolenie: Administracja, replikacja i tuning baz danych PostgreSQL

To szkolenie może być dofinansowane z KFS lub BUR.

★★★★★Średnia ocena naszych szkoleń w Google: 5/5

Szkolenie Zaawansowana administracja PostgreSQL - HA, DR, monitoring, skalowanie

Sprawdź szkolenie: Zaawansowana administracja PostgreSQL (HA, DR, monitoring, skalowanie)

To szkolenie może być dofinansowane z KFS lub BUR.

★★★★★Średnia ocena naszych szkoleń w Google: 5/5

Najczęściej zadawane pytania

Czy mogę zrobić point-in-time recovery, jeśli wcześniej nie włączyłem archiwizacji WAL?
Nie. PITR wymaga, by segmenty WAL z okresu od kopii bazowej do momentu awarii były zarchiwizowane. Archiwizacji nie da się włączyć wstecz, bo PostgreSQL po pewnym czasie kasuje stare segmenty WAL. Bez wcześniej ustawionego archive_mode i archive_command jedyne, co odtworzysz, to stan z ostatniej kopii bazowej.
Jak wskazać moment, do którego ma zostać odtworzona baza?
W postgresql.conf ustawiasz recovery_target_time na konkretną datę i godzinę, na przykład recovery_target_time = '2026-09-28 14:31:59'. Zamiast czasu możesz podać recovery_target_xid (numer transakcji) albo recovery_target_name, jeśli wcześniej oznaczyłeś punkt funkcją pg_create_restore_point. Do wejścia w tryb odtwarzania potrzebny jest też pusty plik recovery.signal w katalogu danych.
Dlaczego baza po odtworzeniu jest tylko do odczytu i jak ją odblokować?
Domyślnie po osiągnięciu celu PostgreSQL zatrzymuje odtwarzanie i pauzuje, żebyś zdążył sprawdzić dane, zanim je utrwalisz. Gdy stan jest właściwy, promujesz bazę do trybu zapisu przez SELECT pg_wal_replay_resume() albo ustawiając wcześniej recovery_target_action = 'promote'. Stan sprawdzisz zapytaniem pg_is_in_recovery: true oznacza tryb odczytu, false to baza gotowa do zapisu.
Co zrobić z bazą tuż po udanym PITR?
Wykonaj świeżą kopię bazową odtworzonego klastra. Po PITR zmienia się linia czasu WAL i wcześniejsze archiwum nie jest już w pełni spójne z nową bazą. Nowa kopia bazowa daje czysty punkt startowy dla kolejnych backupów i przyszłych odtworzeń.

Komentarze (0)

Musisz być zalogowany by móc dodać komentarz. Zaloguj się przez Google

Brak komentarzy...