Blog JSystems - uwalniamy wiedzę!
Blog JSystems - uwalniamy wiedzę!
PostgreSQL
Jak awaryjnie rozłączyć sesję (pg_terminate_backend)
pg_stat_activity i awaryjnie kończymy sesję funkcją pg_terminate_backend(pid), która wysyła sygnał SIGTERM.Prędzej czy później trafisz na sytuację, w której jedna sesja "wisi" i psuje pracę wszystkim pozostałym. Pokażemy Ci, jak ją namierzyć i bezpiecznie odłączyć, oraz kiedy sięgnąć po pg_terminate_backend, a kiedy wystarczy łagodniejszy sposób.
Aplikacja przestaje odpowiadać na operacje na jednej tabeli, choć serwer nie jest obciążony. W monitoringu widzisz połączenie, które od kilkudziesięciu minut jest w stanie idle in transaction - ktoś otworzył transakcję i jej nie zamknął. Innym razem próba DROP TABLE albo ALTER TABLE stoi w nieskończoność, bo czeka na blokadę trzymaną przez zawieszoną sesję. Bywa też, że proces po stronie klienta został ubity, a mimo to backend w PostgreSQL wciąż żyje i blokuje zasoby. W każdym z tych przypadków sesja sama się nie posprząta i trzeba ją zakończyć ręcznie.
PostgreSQL uruchamia dla każdego połączenia osobny proces (backend). Ten proces żyje tak długo, jak długo trwa połączenie - serwer nie ma powodu, by kończyć go tylko dlatego, że "nic nie robi". Jeśli klient otworzył transakcję i porzucił ją bez COMMIT lub ROLLBACK, transakcja trzyma blokady i blokuje odzyskiwanie martwych krotek przez VACUUM. Gdy sieć padnie, a serwer nie ma jeszcze włączonego wykrywania zerwanych połączeń (tcp_keepalives_idle), backend potrafi czekać na klienta w nieskończoność. Domyślnie nie ma też limitu czasu na porzuconą transakcję - dopóki nie ustawisz idle_in_transaction_session_timeout, takie sesje będą wisieć aż ktoś je rozłączy.
SELECT pid, usename, state, now() - state_change AS od_kiedy, left(query, 60) AS zapytanie FROM pg_stat_activity WHERE state <> 'idle' ORDER BY state_change;state (szczególnie idle in transaction), wait_event_type, application_name i czas w state_change. Upewnij się, że to faktycznie martwa albo blokująca sesja, a nie ważny, długi raport w toku.pg_blocking_pids(pid) zwróci listę procesów, które trzymają blokadę oczekiwaną przez dany PID - to pomaga potwierdzić, kto jest źródłem, a kto ofiarą.SELECT pg_cancel_backend(<pid>);. To wysyła SIGINT i przerywa polecenie bez rozłączania klienta.SELECT pg_terminate_backend(<pid>);. Funkcja wysyła SIGTERM, backend robi ROLLBACK otwartej transakcji i się zamyka.pg_signal_backend - tę drugą warto nadać administratorowi aplikacyjnemu, żeby nie logować się jako superuser.idle_in_transaction_session_timeout (np. '5min'), rozważ statement_timeout dla ról aplikacyjnych i włącz tcp_keepalives_idle, żeby serwer sam wykrywał zerwane połączenia.Funkcja zwraca true, jeśli sygnał został wysłany. Zaraz potem wykonaj ponownie zapytanie do pg_stat_activity i upewnij się, że danego pid już nie ma na liście - to znaczy, że backend faktycznie się zakończył (zwrócenie true oznacza tylko, że sygnał doszedł, nie że proces zniknął w tej samej milisekundzie). Sprawdź też, że zablokowane wcześniej polecenie ruszyło z miejsca, a pg_blocking_pids dla ofiary zwraca już pustą tablicę. Jeśli PID uparcie zostaje, poczekaj chwilę i sprawdź ponownie - sesja utknięta na nieprzerywalnej operacji systemowej może potrzebować kilku sekund.
Wróć do listy: 100 najczęstszych pytań i problemów z 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

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
Komentarze (0)
Brak komentarzy...