Blog JSystems - uwalniamy wiedzę!

Szukaj

PostgreSQL

Po co jest WAL i jak działają checkpointy

W skrócie

  • Nie rozumiesz, po co PostgreSQL zapisuje wszystko dwa razy i dlaczego co jakiś czas dysk nagle mocno pracuje.
  • To dziennik WAL (Write-Ahead Log) chroni dane przed utratą przy awarii, a checkpoint co jakiś czas zrzuca zmienione strony z pamięci na dysk danych.
  • Zrozumienie tej mechaniki pozwala świadomie ustawić max_wal_size i checkpoint_completion_target, żeby wygładzić skoki obciążenia dysku.

WAL i checkpointy to fundament trwałości danych w PostgreSQL, a jednocześnie temat, który najczęściej działa jak czarna skrzynka. Wyjaśnimy, co dokładnie dzieje się przy zapisie, dlaczego dziennik istnieje i jak nad nim zapanować, żeby serwer nie zamierał regularnie na kilka sekund.

Jak to wygląda w praktyce

Widzisz, że katalog pg_wal potrafi urosnąć do kilku gigabajtów, choć baza danych jest mała. Co kilka minut monitoring pokazuje skok zapisu na dysk i chwilowe pogorszenie czasów odpowiedzi, a w logu serwera pojawiają się wpisy o checkpointach. Czasem widzisz ostrzeżenie checkpoints are occurring too frequently z sugestią, żeby zwiększyć max_wal_size. Zastanawiasz się, czy to normalne i czy można to okiełznać, żeby aplikacja nie odczuwała tych falowań.

Dlaczego tak się dzieje

PostgreSQL nie zapisuje każdej zmiany od razu w pliki tabel. Gdy modyfikujesz wiersz, zmiana trafia najpierw do strony w pamięci podręcznej (shared buffers) i do dziennika WAL na dysku. Zasada Write-Ahead Logging mówi, że zapis do dziennika musi trafić na dysk, zanim potwierdzimy transakcję. Dzięki temu, jeśli serwer padnie, przy starcie odtworzy z WAL wszystkie potwierdzone zmiany, których nie zdążył zapisać w plikach danych. To właśnie dlatego COMMIT jest trwały nawet po nagłym wyłączeniu prądu.

Strony zmienione w pamięci, ale jeszcze niezapisane do plików danych, nazywamy brudnymi (dirty). Checkpoint to moment, w którym serwer zrzuca wszystkie brudne strony na dysk danych i zapisuje w WAL znacznik mówiący, że do tego punktu wszystko jest już w plikach. Po checkpoincie starsze segmenty WAL nie są już potrzebne do odtwarzania i mogą zostać skasowane albo ponownie użyte. Skok obciążenia, który widzisz, to właśnie ten zrzut brudnych stron. Im rzadszy checkpoint, tym więcej brudnych stron się nazbiera i tym większy jednorazowy skok.

Jak to rozwiązać krok po kroku

  1. Sprawdź bieżące ustawienia poleceniem SHOW max_wal_size; oraz SHOW checkpoint_timeout;. Domyślnie checkpoint wywołuje się co 5 minut albo gdy przyrost WAL przekroczy max_wal_size (domyślnie 1 GB), zależnie co nastąpi wcześniej.
  2. Jeśli w logu widzisz ostrzeżenie o zbyt częstych checkpointach, zwiększ max_wal_size, na przykład do 4GB lub 8GB. Rzadsze checkpointy oznaczają mniej powtarzanych zapisów tych samych stron, kosztem dłuższego odtwarzania po awarii.
  3. Ustaw checkpoint_completion_target na wartość 0.9. To rozkłada zrzut brudnych stron na 90 procent czasu do następnego checkpointu, zamiast robić go w jednym gwałtownym ataku na dysk. Skok obciążenia zamienia się w łagodne, rozłożone w czasie zapisy.
  4. Przeładuj konfigurację poleceniem SELECT pg_reload_conf();. Oba te parametry działają po reloadzie, restart nie jest potrzebny.
  5. Włącz logowanie checkpointów, ustawiając log_checkpoints = on (w nowszych wersjach jest to domyślne). Dzięki temu w logu zobaczysz, ile stron zapisał każdy checkpoint i ile trwał, co pozwala ocenić, czy tuning pomógł.
  6. Nie ograniczaj rozmiaru pg_wal ręcznym kasowaniem plików. Nigdy nie usuwaj plików z tego katalogu samodzielnie, bo skasowanie potrzebnego segmentu uszkodzi bazę. Rozmiarem steruj wyłącznie parametrami.

Jak sprawdzić, że zadziałało

Po zmianach obserwuj log serwera przez kilka godzin normalnego ruchu. Ostrzeżenie checkpoints are occurring too frequently powinno zniknąć, a odstępy między checkpointami wydłużyć się do wartości checkpoint_timeout. W wpisach checkpoint complete zwróć uwagę na pole write - czas zapisu powinien być zbliżony do iloczynu checkpoint_timeout i checkpoint_completion_target, co potwierdza, że zapisy są rozłożone, a nie skumulowane. Statystyki checkpointów podejrzysz też zapytaniem do widoku pg_stat_bgwriter (w PostgreSQL 17 i nowszych część tych kolumn znajdziesz w pg_stat_checkpointer): rosnąca kolumna checkpoints_timed przy niewielkiej checkpoints_req oznacza, że checkpointy wywołuje głównie zegar, a nie zapełnianie WAL - dokładnie o to nam chodziło.

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

Po co PostgreSQL zapisuje zmiany do WAL, skoro i tak trzyma je w plikach tabel?
Ponieważ zapis do plików tabel nie następuje od razu przy każdej transakcji. Zmiana najpierw trafia do dziennika WAL na dysku i do pamięci podręcznej, a dopiero checkpoint zrzuca ją do plików danych. Dzięki temu, jeśli serwer padnie przed zrzutem, przy starcie odtworzy z WAL wszystkie potwierdzone zmiany. To właśnie WAL sprawia, że COMMIT jest trwały nawet po nagłym zaniku zasilania.
Czym jest checkpoint w PostgreSQL i dlaczego widzę przy nim skok obciążenia dysku?
Checkpoint to moment, w którym serwer zrzuca na dysk danych wszystkie zmienione strony trzymane dotąd w pamięci, czyli tak zwane strony brudne. Ten zrzut to właśnie skok zapisu, który obserwujesz. Im rzadszy checkpoint, tym więcej brudnych stron się nazbiera i tym większy jednorazowy skok. Rozłożenie go w czasie ustawia się parametrem checkpoint_completion_target.
Dlaczego w logu widzę ostrzeżenie, że checkpointy występują zbyt często?
To znaczy, że przyrost WAL przekracza max_wal_size, zanim minie czas checkpoint_timeout, więc checkpointy wywołuje zapełnianie dziennika, a nie zegar. Zbyt częste checkpointy powodują wielokrotne zapisywanie tych samych stron. Zwiększ max_wal_size, na przykład do kilku gigabajtów, a ostrzeżenie zniknie i checkpointy będą wywoływane głównie przez upływ czasu.
Czy mogę ręcznie kasować pliki z katalogu pg_wal, żeby odzyskać miejsce na dysku?
Nie, nigdy nie usuwaj plików z pg_wal samodzielnie. Skasowanie segmentu, który jest jeszcze potrzebny do odtwarzania albo do replikacji, uszkodzi bazę. Rozmiarem tego katalogu steruj wyłącznie parametrami takimi jak max_wal_size i przez politykę retencji, a nie ręcznym usuwaniem plików.

Komentarze (0)

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

Brak komentarzy...