Gibt es eine Zeitüberschreitung für inaktive PostgreSQL-Verbindungen?

93
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             

Ich sehe viele von ihnen. Wir versuchen, unser Verbindungsleck zu beheben. In der Zwischenzeit möchten wir eine Zeitüberschreitung für diese Leerlaufverbindungen festlegen, möglicherweise maximal 5 Minuten.

user1012451
quelle
Wie verbindest du dich mit der DB? socketTimeout könnte das sein, wonach Sie suchen.
Doon
Wir haben diese alte Pylons-Web-App und wir haben SQLAlchemy verwendet, aber anscheinend haben wir sie nicht richtig verwendet. Ich erinnere mich nicht. Wir versuchen das Leck zu beheben. socketTimeoutAus dem Dokument geht hervor, dass die Verbindung zur Datenbank vollständig geschlossen wird. Ich versuche, jeden Leerlauf zu schließen, und der Zähler startet, sobald die Verbindung hergestellt ist.
user1012451
@ user1012451 Wenn Sie "jeden Leerlauf schließen" sagen, meinen Sie damit, <IDLE> in transactionSitzungen zu beenden und die Sitzung laufen zu lassen, aber im <IDLE>Status? Mit anderen Worten, die Transaktion beenden, aber nicht die Sitzung? (Abgestimmt: unklare Frage)
Craig Ringer
@CraigRinger Nach einer Weile erreichen wir die maximale Client-Verbindung. Um dies zu lösen, müssen wir die Webanwendung neu starten, wodurch auch postgresql neu gestartet werden muss. Das löscht jede Verbindung aus. Wenn wir diese idlefür immer sehen, fragen wir, ob wir für jede Verbindung / Sitzung eine Zeitüberschreitung festlegen könnten (ich kenne ehrlich gesagt nicht die richtige Terminologie, sorry). Wenn eine Transaktion für eine normale Web-App 5 Minuten dauert, muss etwas falsch sein ....
user1012451

Antworten:

118

Es hört sich so an, als hätten Sie ein Verbindungsleck in Ihrer Anwendung, weil gepoolte Verbindungen nicht geschlossen werden können . Sie haben nicht nur Probleme mit <idle> in transactionSitzungen, sondern insgesamt mit zu vielen Verbindungen.

Das Beenden von Verbindungen ist nicht die richtige Antwort darauf, aber es ist eine vorübergehende Problemumgehung.

Anstatt PostgreSQL neu zu starten, um alle anderen Verbindungen von einer PostgreSQL-Datenbank zu starten, lesen Sie: Wie trenne ich alle anderen Benutzer von einer Postgres-Datenbank? und Wie lösche ich eine PostgreSQL-Datenbank, wenn aktive Verbindungen zu ihr bestehen? . Letzteres zeigt eine bessere Abfrage.

Informationen zum Festlegen von Zeitüberschreitungen, wie von @Doon vorgeschlagen, finden Sie unter So schließen Sie inaktive Verbindungen in PostgreSQL automatisch. Hiermit wird empfohlen, PgBouncer als Proxy für PostgreSQL zu verwenden und inaktive Verbindungen zu verwalten. Dies ist eine sehr gute Idee, wenn Sie eine fehlerhafte Anwendung haben, die ohnehin Verbindungen verliert. Ich empfehle dringend , PgBouncer zu konfigurieren.

Ein TCP-Keepalive erledigt den Job hier nicht, da die App noch verbunden und lebendig ist, sollte es einfach nicht sein.

In PostgreSQL 9.2 und höher können Sie die neue state_changeZeitstempelspalte und das stateFeld von verwenden pg_stat_activity, um einen Reaper für Leerlaufverbindungen zu implementieren. Lassen Sie einen Cron-Job so etwas ausführen:

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;

In älteren Versionen müssen Sie komplizierte Schemata implementieren, die verfolgen, wann die Verbindung unterbrochen wurde. Kümmern Sie sich nicht; benutze einfach pgbouncer.

Craig Ringer
quelle
4
Gut, aber es wird andere PgAdmin-Backends töten. Verwenden Sie die zusätzliche Bedingung application_name = ''
Andrew Selivanov
Kann ich pg_terminate_backend ausführen, wenn ich pgbouncer verwende?
Henley Chiu
@ HenleyChiu Ich verstehe nicht warum nicht, obwohl ich nicht speziell überprüft habe.
Craig Ringer
1
Das Ausführen scheint meinen WAL-Absenderprozess beendet zu haben
Joseph Persie
@CraigRinger sogar eine psql-Verbindung wird als inaktive Verbindung betrachtet. Und warum muss man die Leerlaufverbindung zuerst schließen. Ich habe einen lang laufenden Code, der eine Verbindung mit pg herstellt. Führen Sie eine dml-Operation aus und warten Sie dann auf die Nachricht über der Warteschlange und führen Sie dann eine weitere dml-Operation aus. Jetzt während dieser Zeit, dh während sie über der Warteschlange wartet (auf Nachricht), wie oben erwähnt auch dann ist die verbindung mit postges idle. Warum sollte ich es schließen?
Viren
70

In PostgreSQL 9.6 gibt es eine neue Option, idle_in_transaction_session_timeoutdie das erreichen soll, was Sie beschreiben. Sie können es mit dem SETBefehl einstellen , zB:

SET SESSION idle_in_transaction_session_timeout = '5min';
shosti
quelle
1
Es ist schade, etwas so Einfaches fragen zu müssen, aber ich bin ganz neu in Datenbanken im Allgemeinen. Könnten Sie bitte ein sehr einfaches Beispiel für die Verwendung dieser Funktion geben?
SG
So etwas in früheren Versionen von PostgreSQL?
SDSC81
Nein, für frühere Versionen ist etwas Ähnliches wie für die anderen Antworten erforderlich.
Shosti
Müssen Sie diesen Parameter bei jedem Neustart der Datenbank festlegen? Oder nachdem du es einmal getan hast, kannst du es vergessen? Danke
Fresko
5
SET SESSIONist nur für die aktuelle Sitzung vorgesehen (sobald Sie eine neue Verbindung herstellen, wird die Standardeinstellung wiederhergestellt). Sie können Konfigurationsparameter auch auf Datenbankebene festlegen, indem Sie z. B. ALTER DATABASE SET idle_in_transaction_session_timeout = '5min'oder Konfigurationsdateien verwenden (siehe postgresql.org/docs/current/static/config-setting.html ).
Shosti
22

In PostgreSQL 9.1 werden die inaktiven Verbindungen mit der folgenden Abfrage ausgeführt. Es hat mir geholfen, die Situation abzuwehren, die einen Neustart der Datenbank rechtfertigte. Dies geschieht meistens, wenn JDBC-Verbindungen geöffnet und nicht ordnungsgemäß geschlossen werden.

SELECT
   pg_terminate_backend(procpid)
FROM
   pg_stat_activity
WHERE
   current_query = '<IDLE>'
AND
   now() - query_start > '00:10:00';
sramay
quelle
1
pg_terminate_backend ist in seit 8.4
Andrew Banks
8

Wenn Sie postgresql 9.6+ verwenden, können Sie dies in Ihrer postgresql.conf festlegen

idle_in_transaction_session_timeout = 30000 (ms)

Bertrand David
quelle