Blog JSystems - uwalniamy wiedzę!

Szukaj

PostgreSQL

Dysk pełny - PostgreSQL przestał przyjmować zapisy

W skrócie

  • Dysk z danymi PostgreSQL zapełnił się do końca, baza zaczęła zwracać błąd no space left on device i nie przyjmuje już zapisów.
  • Miejsce zajęły dane, indeksy, spuchnięte tabele, rosnący pg_wal albo pliki tymczasowe. Bez wolnego miejsca silnik nie może zapisać WAL, więc wstrzymuje operacje zapisu.
  • Najpierw szybko odzyskaj trochę miejsca (logi, pliki tymczasowe), potem znajdź i usuń realną przyczynę wzrostu, a na koniec zabezpiecz się monitoringiem.

Pełny dysk to sytuacja awaryjna, która potrafi zatrzymać całą bazę. Dobra wiadomość: PostgreSQL zaprojektowano tak, by w takim wypadku chronić dane, a nie je uszkadzać. Zła: musisz działać szybko i we właściwej kolejności. Pokazujemy, jak odblokować bazę i nie pogorszyć sytuacji.

Jak to wygląda w praktyce

W logu i w odpowiedziach do aplikacji pojawia się ERROR: could not extend file ... No space left on device albo PANIC: could not write to file "pg_wal/...". Zapisy przestają przechodzić, choć odczyty często jeszcze działają. W skrajnym przypadku, gdy zabraknie miejsca na WAL, PostgreSQL może się zatrzymać, żeby nie ryzykować niespójności. Polecenie systemowe df -h na wolumenie z PGDATA pokazuje 100 procent zajętości.

Dlaczego tak się dzieje

PostgreSQL musi zapisać zmianę najpierw do WAL, a potem do plików danych. Gdy na dysku nie ma miejsca, nie może zrobić ani jednego, ani drugiego - dlatego wstrzymuje zapisy zamiast ryzykować uszkodzenie. Miejsce mogło się skończyć z kilku niezależnych powodów, które często występują razem.

Typowi winowajcy to: naturalny wzrost danych i indeksów, spuchnięte tabele (bloat) z powodu niedziałającego VACUUM, rosnący pg_wal (nieaktywny slot replikacji albo padnięta archiwizacja), duże pliki tymczasowe generowane przez ciężkie zapytania sortujące przy zbyt małym work_mem, oraz nadmierne logi serwera, jeśli logujesz wszystko do wolumenu z danymi. Kluczowe jest, żeby najpierw odblokować bazę niewielką ilością wolnego miejsca, a dopiero potem zająć się główną przyczyną.

Jak to rozwiązać krok po kroku

  1. Szybko odzyskaj trochę miejsca poza katalogami danych. Sprawdź logi serwera i systemu (katalog logów PostgreSQL, dzienniki systemowe) i skompresuj albo przenieś stare pliki logów na inny wolumen. To zwykle najszybszy sposób na kilka wolnych gigabajtów bez ryzyka.
  2. Zidentyfikuj, co zajmuje najwięcej miejsca w bazie: SELECT relname, pg_size_pretty(pg_total_relation_size(oid)) AS rozmiar FROM pg_class WHERE relkind IN ('r','m') ORDER BY pg_total_relation_size(oid) DESC LIMIT 20;. Rozmiary całych baz: SELECT datname, pg_size_pretty(pg_database_size(datname)) FROM pg_database ORDER BY pg_database_size(datname) DESC;.
  3. Sprawdź, czy problemem nie jest pg_wal. Jeśli tak, znajdź i usuń nieaktywny slot replikacji (SELECT slot_name, active FROM pg_replication_slots; i SELECT pg_drop_replication_slot('nazwa');) albo napraw archiwizację - to często uwalnia najwięcej miejsca naraz.
  4. Skasuj oczywiste śmieci w bazie: niepotrzebne stare tabele, duże tabele tymczasowe albo dane, które i tak miały być usunięte. Po usunięciu wierszy pamiętaj, że zwykły DELETE nie zwolni miejsca fizycznie - potrzebny będzie VACUUM FULL lub pg_repack, gdy już odzyskasz trochę zapasu.
  5. Gdy masz już kilka wolnych gigabajtów, zajmij się bloatem: uruchom VACUUM FULL albo pg_repack na najbardziej spuchniętych tabelach, aby fizycznie zmniejszyć pliki i oddać miejsce systemowi.
  6. Jeśli miejsca fizycznie brakuje na dobre, rozważ powiększenie wolumenu albo przeniesienie części danych na inny dysk przez przestrzeń tabel (tablespace): CREATE TABLESPACE dane2 LOCATION '/mnt/dysk2/pg'; i ALTER TABLE duza_tabela SET TABLESPACE dane2;.

Jak sprawdzić, że zadziałało

Po odzyskaniu miejsca sprawdź zajętość wolumenu z PGDATA poleceniem df -h - powinna spaść poniżej progu alarmowego. Przetestuj zwykły zapis, np. CREATE TABLE test_zapis(x int); INSERT INTO test_zapis VALUES (1); DROP TABLE test_zapis; - powinien przejść bez błędu no space left on device. Zajrzyj do logu i upewnij się, że komunikaty o braku miejsca ustały. Na koniec ustaw w monitoringu alert na zajętość dysku (np. przy 80 procentach), aby następnym razem zareagować, zanim baza się zatrzyma.

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 pełny dysk może uszkodzić bazę PostgreSQL?
Zwykle nie, bo PostgreSQL celowo wstrzymuje zapisy, gdy nie może zapisać WAL, zamiast ryzykować niespójność. Dane pozostają bezpieczne, ale baza przestaje przyjmować zapisy, dopóki nie odzyskasz wolnego miejsca.
Od czego zacząć, gdy dysk z PostgreSQL jest pełny?
Najpierw odzyskaj kilka gigabajtów poza danymi, na przykład kompresując lub przenosząc stare logi. Dopiero mając zapas, szukaj głównej przyczyny: bloatu, rosnącego pg_wal albo dużych tabel, i usuwaj ją bezpiecznie.
Dlaczego usunięcie wierszy nie zwolniło miejsca na dysku?
Zwykły DELETE tylko oznacza wiersze jako martwe w ramach MVCC. Fizyczne miejsce w pliku odzyskasz dopiero przez VACUUM FULL albo pg_repack, które przepisują tabelę i oddają niewykorzystane strony systemowi plików.
Jak przenieść część danych na inny dysk, gdy brakuje miejsca?
Utwórz przestrzeń tabel na drugim wolumenie poleceniem CREATE TABLESPACE ze wskazaniem lokalizacji, a potem przenieś wybrane tabele przez ALTER TABLE SET TABLESPACE. To rozkłada dane na więcej niż jeden dysk.

Komentarze (0)

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

Brak komentarzy...