it-swarm.com.de

Wie werden inaktive Verbindungen in PostgreSQL automatisch geschlossen?

Einige Clients stellen eine Verbindung zu unserer Postgresql-Datenbank her, lassen aber die Verbindungen geöffnet. Ist es möglich, Postgresql anzuweisen, diese Verbindung nach einer gewissen Inaktivität zu schließen?

TL; DR

WENN Sie eine Postgresql-Version verwenden> = 9.2
DANN benutze die Lösung, die ich mir ausgedacht habe

WENN Sie keinen Code schreiben möchten
DANN benutze die Lösung von arqnid

32
Stephan

Für diejenigen, die daran interessiert sind, hier ist die Lösung, die ich gefunden habe, inspiriert von Craig Ringer s Kommentar:

(...) Verwenden Sie einen cron-Job, um zu sehen, wann die Verbindung zuletzt aktiv war (siehe pg_stat_activity), und verwenden Sie pg_terminate_backend, um alte Verbindungen zu beenden. (...)

Die gewählte Lösung sieht so aus:

  • Zuerst aktualisieren wir auf Postgresql 9.2.
  • Dann planen wir einen Thread, der jede Sekunde ausgeführt wird.
  • Wenn der Thread ausgeführt wird, sucht er nach alten inaktiven Verbindungen .
    • Eine Verbindung gilt als inaktiv, wenn ihr Zustand entweder idle, idle in transaction, idle in transaction (aborted) oder disabled ist.
    • Eine Verbindung wird als old betrachtet, wenn ihr Status länger als 5 Minuten unverändert geblieben ist.
  • Es gibt zusätzliche Threads, die das gleiche wie oben tun. Diese Threads stellen jedoch mit einem anderen Benutzer eine Verbindung zur Datenbank her.
  • Wir lassen mindestens eine Verbindung für jede Anwendung offen, die mit unserer Datenbank verbunden ist. (rank() Funktion)

Dies ist die SQL-Abfrage, die vom Thread ausgeführt wird:

WITH inactive_connections AS (
    SELECT
        pid,
        rank() over (partition by client_addr order by backend_start ASC) as rank
    FROM 
        pg_stat_activity
    WHERE
        -- Exclude the thread owned connection (ie no auto-kill)
        pid <> pg_backend_pid( )
    AND
        -- Exclude known applications connections
        application_name !~ '(?:psql)|(?:pgAdmin.+)'
    AND
        -- Include connections to the same database the thread is connected to
        datname = current_database() 
    AND
        -- Include connections using the same thread username connection
        usename = current_user 
    AND
        -- Include inactive connections only
        state in ('idle', 'idle in transaction', 'idle in transaction (aborted)', 'disabled') 
    AND
        -- Include old connections (found with the state_change field)
        current_timestamp - state_change > interval '5 minutes' 
)
SELECT
    pg_terminate_backend(pid)
FROM
    inactive_connections 
WHERE
    rank > 1 -- Leave one connection for each application connected to the database
36
Stephan

Stellen Sie die Verbindung über einen Proxy wie PgBouncer her, der die Verbindung nach server_idle_timeout Sekunden beendet.

11
araqnid

Wenn Sie PostgreSQL> = 9.6 verwenden, gibt es eine noch einfachere Lösung. Angenommen, Sie möchten alle inaktiven Verbindungen alle 5 Minuten löschen. Führen Sie einfach Folgendes aus:

alter system set idle_in_transaction_session_timeout='5min';

Wenn Sie keinen Zugriff als Superuser haben (Beispiel in der Azure Cloud), versuchen Sie Folgendes:

SET SESSION idle_in_transaction_session_timeout = '5min';

Letzteres funktioniert jedoch nur für die aktuelle Sitzung. Dies ist höchstwahrscheinlich nicht das, was Sie wollen.

deaktivieren die Funktion,

alter system set idle_in_transaction_session_timeout=0;

oder

SET SESSION idle_in_transaction_session_timeout = 0;

(übrigens ist 0 der Standardwert).

Wenn Sie alter system verwenden, müssen Sie die Konfiguration erneut laden, um die Änderung zu starten. Die Änderung ist dauerhaft. Sie müssen die Abfrage nicht mehr erneut ausführen, wenn Sie beispielsweise den Server neu starten.

So überprüfen Sie den Funktionsstatus:

show idle_in_transaction_session_timeout;
1
fresko