Czy istnieje limit czasu dla bezczynnych połączeń PostgreSQL?

99
1 S postgres  5038   876  0  80   0 - 11962 sk_wai 09:57 ?        00:00:00 postgres: postgres my_app ::1(45035) idle                                                                                 
1 S postgres  9796   876  0  80   0 - 11964 sk_wai 11:01 ?        00:00:00 postgres: postgres my_app ::1(43084) idle             

Widzę ich dużo. Próbujemy naprawić wyciek połączenia. Ale w międzyczasie chcemy ustawić limit czasu dla tych bezczynnych połączeń, może maksymalnie 5 minut.

user1012451
źródło
jak łączysz się z DB? socketTimeout może być tym, czego szukasz.
Doon
Mamy starszą aplikację internetową Pylons i używaliśmy SQLAlchemy, ale najwyraźniej nie używaliśmy jej poprawnie. Nie pamiętam. Próbujemy naprawić wyciek. socketTimeoutz dokumentu wygląda na to, że całkowicie zamknę połączenie z bazą danych. Próbuję zamknąć każdy bezczynność, a licznik uruchamia się, gdy tylko zostanie nawiązane połączenie.
user1012451
@ user1012451 Kiedy mówisz „zamknij każde bezczynne” - czy masz na myśli zakończenie <IDLE> in transactionsesji, pozostawiając sesję działającą, ale w <IDLE>stanie? Innymi słowy, zakończyć transakcję, ale nie zakończyć sesję? (Z głosem negatywnym: niejasne pytanie)
Craig Ringer
@CraigRinger po chwili osiągamy maksymalne połączenie klienta. Aby rozwiązać ten problem, musimy ponownie uruchomić aplikację internetową, co wymusza również ponowne uruchomienie postgresql. To wymazuje każde połączenie. Kiedy widzimy je w idlenieskończoność, pytamy, czy moglibyśmy ustawić limit czasu dla każdego połączenia / sesji (szczerze mówiąc nie znam poprawnej terminologii, przepraszam). Jeśli transakcja trwa 5 minut w przypadku normalnej aplikacji internetowej, coś musi być nie tak ...
user1012451

Odpowiedzi:

120

Wygląda na to, że w aplikacji występuje przeciek połączenia, ponieważ nie zamyka ona połączeń w puli . Nie masz problemów tylko z <idle> in transactionsesjami, ale ogólnie ze zbyt dużą liczbą połączeń.

Zabijanie połączeń nie jest na to właściwą odpowiedzią, ale jest to w porządku tymczasowe obejście.

Zamiast ponownie uruchamiać PostgreSQL w celu uruchomienia wszystkich innych połączeń z bazy danych PostgreSQL, zobacz: Jak odłączyć wszystkich innych użytkowników od bazy danych postgres? i jak usunąć bazę danych PostgreSQL, jeśli są z nią aktywne połączenia? . Ta ostatnia pokazuje lepsze zapytanie.

Aby ustawić limity czasu, zgodnie z sugestią @Doon, zobacz Jak automatycznie zamykać bezczynne połączenia w PostgreSQL? , który zaleca użycie PgBouncer do proxy dla PostgreSQL i zarządzania bezczynnymi połączeniami. To bardzo dobry pomysł, jeśli masz błędną aplikację, która i tak przecieka połączenia; I bardzo silnie zaleca konfigurowania PgBouncer.

Keepalive TCP nie zrobi pracy tutaj, ponieważ aplikacja jest nadal podłączona i żywy, to po prostu nie powinno być.

W PostgreSQL 9.2 i nowszych możesz użyć nowej state_changekolumny timestamp i statepola of, pg_stat_activityaby zaimplementować bezczynne połączenie. Niech zadanie crona uruchomi coś takiego:

SELECT pg_terminate_backend(pid)
    FROM pg_stat_activity
    WHERE datname = 'regress'
      AND pid <> pg_backend_pid()
      AND state = 'idle'
      AND state_change < current_timestamp - INTERVAL '5' MINUTE;

W starszych wersjach musisz zaimplementować skomplikowane schematy, które śledzą, kiedy połączenie było bezczynne. Nie przejmuj się; po prostu użyj pgbouncer.

Craig Ringer
źródło
4
Dobrze, ale zabije inne backendy PgAdmin. Użyj dodatkowego warunku application_name = ''
Andrew Selivanov
1
Czy mogę uruchomić pg_terminate_backend, jeśli używam pgbouncer?
Henley Chiu,
@HenleyChiu Nie rozumiem, dlaczego nie, chociaż nie sprawdziłem konkretnie.
Craig Ringer
1
Wydaje się, że uruchomienie tego zabiło mój proces wysyłania WAL
Joseph Persie
@CraigRinger nawet połączenie psql jest uważane za bezczynne połączenie. I dlaczego w pierwszej kolejności trzeba zamknąć bezczynne połączenie. Mam długo działający kod, który nawiązuje połączenie z pg, wykonuje jakąś operację dml, a następnie czeka na wiadomość w kolejce, a następnie wykonuje więcej operacji dml.Teraz w tym okresie, tj. Podczas oczekiwania na kolejkę (na wiadomość), jak wspomniano powyżej nawet wtedy jest połączenie z pocztą idle. dlaczego powinienem to zamknąć.
Viren
73

W PostgreSQL 9.6 jest nowa opcja, idle_in_transaction_session_timeoutktóra powinna wykonać to, co opisujesz. Możesz to ustawić za pomocą SETpolecenia np:

SET SESSION idle_in_transaction_session_timeout = '5min';
shosti
źródło
1
Do bani jest zadawanie tak prostych pytań, ale ogólnie jestem zupełnie nowy w bazach danych - czy mógłbyś podać bardzo podstawowy przykład korzystania z tej funkcji?
sg
Coś takiego w poprzednich wersjach PostgreSQL?
sdsc81
Nie, w przypadku poprzednich wersji wymagane jest coś podobnego do innych odpowiedzi.
shosti
Czy musisz ustawiać ten parametr przy każdym restarcie bazy danych? A może po tym, jak kiedyś możesz zapomnieć? Dzięki
fresko
5
SET SESSIONdotyczy tylko bieżącej sesji (wróci do ustawień domyślnych po otwarciu nowego połączenia). Możesz także ustawić parametry konfiguracyjne na poziomie bazy danych używając np. ALTER DATABASE SET idle_in_transaction_session_timeout = '5min'Lub używając plików konfiguracyjnych (patrz postgresql.org/docs/current/static/config-setting.html ).
shosti
22

W PostgreSQL 9.1 bezczynne połączenia z następującym zapytaniem. Pomogło mi to zażegnać sytuację, która uzasadniała ponowne uruchomienie bazy danych. Dzieje się tak głównie w przypadku połączeń JDBC otwartych i nieprawidłowo zamkniętych.

SELECT
   pg_terminate_backend(procpid)
FROM
   pg_stat_activity
WHERE
   current_query = '<IDLE>'
AND
   now() - query_start > '00:10:00';
sramay
źródło
1
pg_terminate_backend jest dostępny od 8.4
Andrew Banks,
8

jeśli używasz postgresql 9.6+, możesz ustawić w swoim postgresql.conf

idle_in_transaction_session_timeout = 30000 (msec)

Bertrand David
źródło
0

Możliwym obejściem, które pozwala włączyć limit czasu sesji bazy danych bez zewnętrznego zaplanowanego zadania, jest użycie rozszerzenia pg_timeout , które opracowałem.

pifor
źródło