Blog JSystems - uwalniamy wiedzę!
Blog JSystems - uwalniamy wiedzę!
PostgreSQL
Stary primary po failoverze nie wraca jako replika - pg_rewind i oś czasu (timeline)
Ten problem dotyczy każdego, kto po awarii przełączył zapis na replikę (failover), a teraz chce przywrócić dawny primary do klastra jako serwer zapasowy. Po kontrolowanym przełączeniu czasem wystarczy dopisać standby.signal i primary_conninfo, ale po awarii stary serwer mógł zdążyć coś zapisać po rozdzieleniu i wtedy to nie działa. Odtworzyliśmy to na PostgreSQL 16 i przeszliśmy całą drogę: od komunikatu w logu, przez kolejne błędy pg_rewind, do repliki strumieniującej na nowej osi czasu. Pokażemy też, co w tej sytuacji robi Patroni.
Dawny primary dostaje plik standby.signal i primary_conninfo wskazujące nowy primary. Startuje, ale w jego logu w kółko powtarza się:
LOG: new timeline 2 forked off current database system timeline 1 before current recovery point 0/82137D0
LOG: started streaming WAL from primary at 0/8000000 on timeline 1
LOG: replication terminated by primary server
DETAIL: End of WAL reached on timeline 1 at 0/820F818.Serwer jest w trybie odtwarzania (pg_is_in_recovery() zwraca t), lecz nie odtwarza niczego z nowego primary. Próba naprawy narzędziem pg_rewind na klastrze utworzonym z domyślnymi ustawieniami kończy się od razu:
pg_rewind: error: target server needs to use either data checksums or "wal_log_hints = on"
Przy każdym awansie repliki PostgreSQL podnosi numer osi czasu (timeline), czyli generacji klastra. Numer jest pierwszym członem nazwy pliku WAL, czyli dziennika zmian: po naszym failoverze nowy primary pisał do 000000020000000000000008, a stary dalej do plików z prefiksem 00000001. Plik 00000002.history zapisuje miejsce w WAL, w którym linie się rozdzieliły (u nas 0/820F818). Stary primary przyjął po tym punkcie jeszcze zapisy, więc ma zmiany, których nowy primary nie zna, i nie może go po prostu dogonić.
Zobacz też: Szkolenie Zaawansowana administracja PostgreSQL: High Availability, Disaster Recovery
pg_rewind cofa katalog danych starego primary do punktu rozejścia. Przegląda jego WAL od ostatniego wspólnego checkpointu, notuje zmienione bloki plików danych i kopiuje je z nowego primary, a pozostałe pliki, w tym konfigurację i WAL, przenosi w całości. Zmiany samych bitów podpowiedzi (hint bits) trafiają do WAL wyłącznie przy wal_log_hints = on albo przy sumach kontrolnych stron (initdb --data-checksums), a żadne z nich nie jest domyślnie włączone. wal_log_hints ma kontekst postmaster, więc wymaga restartu i trzeba go włączyć przed awarią. Narzędzie potrzebuje też plików WAL starego primary od tego checkpointu, a nowy primary musi mieć włączone full_page_writes.
pg_controldata /sciezka/pgdata | grep -E 'wal_log_hints|checksum'. Przy wal_log_hints setting: off i Data page checksum version: 0 pg_rewind odmówi pracy. Na nowym primary musi też działać full_page_writes = on (wartość domyślna), inaczej dostaniesz pg_rewind: error: full_page_writes must be enabled in the source server. Gdy wal_log_hints i sumy kontrolne są wyłączone, zbuduj replikę od nowa (pg_basebackup albo patronictl reinit w Patroni) i na przyszłość ustaw wal_log_hints = on na wszystkich węzłach, z restartem.postgres jako superuser albo rola z prawem wykonania funkcji pg_ls_dir, pg_stat_file i pg_read_binary_file, plus wpis w pg_hba.conf i SELECT pg_reload_conf();.pg_rewind --target-pgdata=/sciezka/pgdata --source-server='host=NOWY_PRIMARY port=5432 user=postgres dbname=postgres' --restore-target-wal --dry-run. Opcja --restore-target-wal (-c) pobiera brakujące pliki WAL z archiwum przez restore_command ustawiony na starym primary. Bez niej dostaliśmy could not open file ".../pg_wal/000000010000000000000002": No such file or directory, a bez restore_command błąd restore_command is not set in the target cluster. Poprawny wynik kończy się linią pg_rewind: Done!.--dry-run, z --write-recovery-conf (-R). pg_rewind utworzy standby.signal i dopisze primary_conninfo do postgresql.auto.conf. Pliki konfiguracyjne kopiuje z nowego primary, więc przed startem przejrzyj postgresql.auto.conf, bo u nas trafiły tam ustawienia właściwe tylko dla tamtego serwera.use_pg_rewind: true w konfiguracji dynamicznej (patronictl edit-config), a Patroni sam wywoła pg_rewind, gdy dawny lider dołącza jako replika. Opcja remove_data_directory_on_rewind_failure w sekcji postgresql pozwala mu przy nieudanym przewinięciu usunąć katalog danych i zbudować replikę od nowa.Na dawnym primary, teraz replice, sprawdź tryb pracy i oś czasu, z której odbiera WAL:
shop=# SELECT pg_is_in_recovery();
pg_is_in_recovery
-------------------
t
(1 row)
shop=# SELECT status, received_tli FROM pg_stat_wal_receiver;
status | received_tli
-----------+--------------
streaming | 2
(1 row)received_tli = 2 oznacza odbiór WAL z nowej osi czasu. W logu pojawia się started streaming WAL from primary at ... on timeline 2, a na nowym primary SELECT application_name, state FROM pg_stat_replication; pokazuje tę replikę ze stanem streaming.
Wróć do listy: 112 najczęstszych pytań i problemów z PostgreSQL
Komentarze (0)
Brak komentarzy...