Jedną z interesujących funkcji PostgreSQL od wersji 9.4 jest możliwość kontrolowania usuwania plików WAL za pomocą gniazd replikacji. Ciemną stroną jest to, że gniazda replikacji mogą powodować zapełnianie dysków starym WAL-em, zabijając główny serwer produkcyjny. W tym artykule wyjaśniam gniazda replikacji PostgreSQL i jak nowa funkcja PostgreSQL 13 pomaga zapobiegać temu problemowi.
Produkcja WAL
Jak wiecie, WAL jest tworzony dla zmian w bazie danych na serwerze głównym:wstawek, aktualizacji, i tak dalej . Bardziej aktywna baza danych wygeneruje więcej WAL — na bardzo aktywnym serwerze może być produkowanych wiele gigabajtów WAL na minutę. WAL jest zapisywany do plików o nazwach w rosnącej kolejności numerycznej, a pliki mają zawsze ten sam rozmiar (domyślnie i typowo 16 MB). Gdy dane w pliku nie są już potrzebne, można go odzyskać , co oznacza zmianę jego nazwy na pozycję o wyższym numerze w sekwencji, aby później można było ją uzupełnić nowymi danymi.
(Istnieją specjalne sytuacje, takie jak wzrost aktywności, który prowadzi do tworzenia dodatkowych plików; gdy później wzrost ten słabnie, te dodatkowe pliki są usuwane, a nie poddawane recyklingowi.)
Ponieważ wszystkie operacje związane z zapisem bazy danych generują WAL, dostępność miejsca na dysku ma kluczowe znaczenie. Gdy dysk przechowujący WAL jest pełny, serwer nie będzie w stanie przetwarzać nowych transakcji i może utknąć lub, co gorsza:może się całkowicie przewrócić. Jest to więc sytuacja, której należy unikać za wszelką cenę.
Gniazda replikacji
Replikacja w PostgreSQL działa na zasadzie przetwarzania plików WAL. Aby to zadziałało, wszystkie pliki WAL muszą być przejściowo dostępne, dopóki nie zostaną przetworzone. Dlatego potrzebny jest mechanizm informujący główne kierownictwo WAL, aby nie odtwarzało ani nie usuwało plików.
Wprowadź gniazda replikacji. Automaty to mechanizm, który wskazuje, że to wykonywana przez nas kopia zapasowa będzie wymagać tego plik WAL i czy możesz go jeszcze nie usuwać; lub to replika nadal nie przetworzyła tego Plik WAL, więc czy można go zostawić w spokoju na chwilę.
Same gniazda replikacji zajmują bardzo mało miejsca na dysku. Przechowują tylko niewielką ilość metadanych, w tym wskaźnik do pozycji w WAL. Ale dane WAL, które chroni, to inna sprawa:w wysoce aktywnym serwerze można je mierzyć w gigabajtach lub gorzej.
Zużycie WAL
Dostarczenie danych do fizycznej repliki oznacza skopiowanie danych WAL z jej głównego serwera. Podobnie replika logiczna musi odczytywać dane WAL (i przesyłać zinterpretowaną wersję do repliki). Odczytywana pozycja WAL jest tym, co slot śledzi. Gdy replika w jakiś sposób zabezpieczy dane WAL, gniazdo można przesunąć; informuje to zarządzanie WAL w systemie podstawowym, że plik WAL jest wtedy dostępny do usunięcia. Dzieje się to w sposób ciągły, gdy replika jest aktywna, tak że WAL na serwerze podstawowym będzie wykorzystywał tę samą ilość miejsca na dysku, a może tylko trochę więcej. Nawet dwa razy więcej lub dziesięć razy więcej może być do przyjęcia, w zależności od warunków.
Problem polega na tym, że jeśli replika całkowicie umrze i nie będzie się regenerować przez długi czas; lub replika jest zniszczona i administrator zapomni usunąć gniazdo replikacji; albo slot jest zapomnianą pozostałością po jakimś eksperymencie; lub nawet replika jest zasilana przez wolne łącze sieciowe, wtedy zarezerwowany WAL będzie rósł bez ograniczeń. A to staje się tykającą bombą.
Ograniczenie rozmiaru boksu
Aby rozwiązać ten problem, Kyotaro Horiguchi pracował od lutego 2017 r. nad łatką PostgreSQL, aby ograniczyć rozmiar WAL zarezerwowany przez slot. Po bardzo długim procesie przeglądu i przeróbek zintegrowałem go z PostgreSQL 13, poprawiając zarządzanie farmami PostgreSQL o wysokiej dostępności.
Główną zasadą jest to, że lepiej zabić replikę (poprzez unieważnienie jej slotu; więcej o tym poniżej) niż zabijać serwer główny, który zasila tę replikę i wyłączać z nią całą produkcję.
Sposób, w jaki to działa, jest dość prosty:ustaw max_slot_wal_keep_size
(dokumentacja) w postgresql.conf do maksymalnej ilości miejsca na dysku WAL, którą mogą zarezerwować gniazda replikacji. Jeśli slot osiągnie ten punkt i wystąpi punkt kontrolny, zostanie on oznaczony jako nieważny i niektóre pliki WAL mogą zostać usunięte. Jeśli slot był aktywnie używany przez walsendera proces, ten proces zostanie zasygnalizowany, aby się zakończył. Jeśli walsender uruchomi się ponownie, okaże się, że niezbędne pliki WAL już tam nie będą. Replika korzystająca z tego gniazda będzie musiała zostać ponownie sklonowana.
Jeśli max_slot_wal_keep_size
wynosi zero, co jest wartością domyślną, wtedy nie ma limitu. Nie polecam tego, ponieważ prowadzi to do awarii, gdy gniazda wypełniają dysk.
Monitorowanie stanu gniazda
Dołączone są również niektóre funkcje monitorowania. Istotne są dwie kolumny w pg_replication_slots. Najważniejszym z nich jest wal_status
. Jeśli ta kolumna jest reserved
, to slot wskazuje na dane w max_wal_size
; jeśli jest extended
potem przekroczył max_wal_size
, ale nadal jest chroniony przez wal_keep_size
lub max_slot_wal_keep_size
(również gdy max_slot_wal_keep_size
wynosi zero). Każdy stan jest dobry i normalny. Jednak gdy slot przekroczy limit, najpierw staje się unreserved
, co oznacza, że jest w bezpośrednim niebezpieczeństwie, ale może się zregenerować, jeśli jest wystarczająco szybkie. Ostatecznie status staje się lost
gdy pliki WAL zostały usunięte i odzyskanie nie jest możliwe.
Druga kolumna to safe_wal_size
:pokazuje liczbę bajtów WAL, które można zapisać, zanim ten slot znajdzie się w niebezpieczeństwie usunięcia plików WAL. Sugerujemy, aby uważnie obserwować tę kolumnę w systemie monitorowania i uruchamiać alerty, gdy stanie się niski. Zero lub minus oznacza, że replika będzie martwa, gdy tylko pojawi się punkt kontrolny:
SELECT slot_name, active, wal_status, safe_wal_size FROM pg_catalog.pg_replication_slots;
Wierzymy, że ta nowa funkcja sprawia, że konserwacja replik jest łatwiejsza i bardziej niezawodna; miejmy nadzieję, że z powodu tych problemów nie zobaczymy już więcej katastrof związanych z przerwą w produkcji.
(Uwaga:safe_wal_size
został wprowadzony w 13beta3, więc zapoznaj się z aktualną dokumentacją, w przeciwnym razie zobaczysz min_safe_lsn
zamiast. Zignoruj to.)
Dzięki
Specjalne podziękowania dla Kyotaro Horiguchi za pracę nad rozwiązaniem tego problemu. Kilku recenzentów zagłębiło się w to, wśród których chciałbym szczególnie podziękować Masahiko Sawada, Fujii Masao, Jehan-Guillaume de Rorthais i Amit Kapila (w dowolnej kolejności).