Blog JSystems - uwalniamy wiedzę!

Szukaj

PostgreSQL

Ostrzeżenie o transaction ID wraparound - jak zareagować

W skrócie

  • W logu pojawia się ostrzeżenie o zbliżającym się transaction ID wraparound, a w skrajnym przypadku baza zaczyna odmawiać zapisów, żeby chronić dane.
  • Identyfikatory transakcji (XID) są 32-bitowe i zataczają koło. VACUUM musi regularnie zamrażać stare wiersze; jeśli tego nie robi, baza zbliża się do granicy, po której straciłaby widoczność danych.
  • Ustal, która baza ma najstarszy XID, uruchom agresywny VACUUM (w razie potrzeby w trybie jednoużytkownikowym) i napraw przyczynę, dla której autovacuum nie zamrażał wierszy.

Transaction ID wraparound to jeden z niewielu problemów PostgreSQL, który potrafi zatrzymać całą bazę. Brzmi groźniej, niż jest w praktyce - o ile zareagujesz na ostrzeżenie i nie zignorujesz go. Tłumaczymy mechanizm i podajemy dokładną procedurę ratunkową.

Jak to wygląda w praktyce

Najpierw w logu widać ostrzeżenia typu WARNING: database "twoja_baza" must be vacuumed within 10000000 transactions. Jeśli je zignorujesz, komunikat staje się coraz bardziej naglący, aż baza wchodzi w tryb ochronny i przy próbie zapisu zwraca ERROR: database is not accepting commands to avoid wraparound data loss. Wtedy działają już tylko odczyty i operacje sprzątające.

Dlaczego tak się dzieje

Każda transakcja dostaje 32-bitowy identyfikator XID. Ponieważ to tylko około 4 miliardów wartości, przestrzeń XID jest traktowana jak okrąg: w danej chwili połowa wartości to przeszłość, a połowa przyszłość. Żeby stare wiersze nie zostały nagle uznane za pochodzące z przyszłości (co oznaczałoby ich zniknięcie), VACUUM zamraża je specjalnym znacznikiem, który mówi silnikowi, że wiersz jest widoczny dla wszystkich.

Jeśli autovacuum z jakiegoś powodu nie zamraża wierszy - bo jest wyłączony, bo długo trwająca transakcja albo porzucony slot replikacji trzyma stary horyzont, albo bo prace blokuje spuchnięta tabela - wiek najstarszego niezamrożonego XID rośnie. Gdy zbliża się do autovacuum_freeze_max_age, PostgreSQL wymusza agresywny autovacuum. Gdy mimo to podejdzie na krytyczną odległość, włącza tryb ochronny, żeby nie doszło do utraty danych.

Jak to rozwiązać krok po kroku

  1. Ustal, która baza jest najbliżej granicy: SELECT datname, age(datfrozenxid) FROM pg_database ORDER BY age(datfrozenxid) DESC;. Wartość bliska 2 miliardom to stan alarmowy. Połącz się z tą bazą do dalszych kroków.
  2. Znajdź konkretne tabele z najstarszym XID: SELECT relname, age(relfrozenxid) FROM pg_class WHERE relkind IN ('r','m','t') ORDER BY age(relfrozenxid) DESC LIMIT 20;. To one wymagają zamrożenia w pierwszej kolejności.
  3. Usuń blokery zamrażania. Sprawdź długie transakcje i porzucone sloty: SELECT pid, state, xact_start FROM pg_stat_activity ORDER BY xact_start; oraz SELECT slot_name, active FROM pg_replication_slots;. Zakończ wiszącą transakcję albo usuń nieużywany slot poleceniem SELECT pg_drop_replication_slot('nazwa');.
  4. Jeśli baza jeszcze przyjmuje polecenia, uruchom agresywny VACUUM zamrażający dla najstarszych tabel: VACUUM (FREEZE, VERBOSE) nazwa_tabeli;, a docelowo dla całej bazy vacuumdb --all --freeze --jobs=4 z linii poleceń.
  5. Jeśli baza weszła już w tryb ochronny i odmawia zapisów, zatrzymaj klaster i wystartuj go w trybie jednoużytkownikowym: postgres --single -D /sciezka/do/pgdata twoja_baza, a następnie w konsoli wykonaj VACUUM FREEZE;. Po zakończeniu wróć do normalnego startu serwera.
  6. Zapobiegaj nawrotom: upewnij się, że autovacuum jest włączony (SHOW autovacuum; ma zwrócić on), monitoruj wiek XID w monitoringu i nie pozostawiaj otwartych transakcji ani martwych slotów replikacji na długo.

Jak sprawdzić, że zadziałało

Po zamrożeniu ponownie sprawdź wiek najstarszego XID: SELECT datname, age(datfrozenxid) FROM pg_database ORDER BY age(datfrozenxid) DESC; - wartości powinny wyraźnie spaść, do rzędu setek tysięcy zamiast miliardów. Ostrzeżenia w logu przestaną się pojawiać. Jeśli baza była w trybie ochronnym, po ponownym starcie przetestuj zwykły zapis, np. INSERT do tabeli testowej - powinien przejść bez błędu. Na koniec potwierdź w pg_class, że age(relfrozenxid) problematycznych tabel jest już niski.

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 transaction ID wraparound grozi utratą danych?
PostgreSQL właśnie po to wchodzi w tryb ochronny i blokuje zapisy, żeby do utraty danych nie dopuścić. Realne ryzyko pojawia się tylko wtedy, gdy administrator ignoruje ostrzeżenia przez bardzo długi czas.
Co zrobić, gdy baza już nie przyjmuje zapisów z powodu wraparound?
Trzeba zatrzymać klaster i uruchomić PostgreSQL w trybie jednoużytkownikowym poleceniem postgres --single, a następnie wykonać VACUUM FREEZE. Po zakończeniu zamrażania baza wraca do normalnej pracy.
Dlaczego autovacuum nie zamroził wierszy na czas?
Najczęstsze przyczyny to wyłączony autovacuum, długo trwająca transakcja lub porzucony slot replikacji trzymający stary horyzont oraz spuchnięte tabele, które blokują szybkie sprzątanie. Trzeba usunąć ten bloker.
Jak monitorować ryzyko wraparound, zanim pojawi się ostrzeżenie?
Regularnie odpytuj age(datfrozenxid) w pg_database i age(relfrozenxid) w pg_class. Ustaw alert w monitoringu, gdy wiek zbliża się do autovacuum_freeze_max_age, czyli domyślnie około 200 milionów transakcji.

Komentarze (0)

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

Brak komentarzy...