web-dev-qa-db-fra.com

Comment fermer automatiquement les connexions inactives dans PostgreSQL?

Certains clients se connectent à notre base de données postgresql mais laissent les connexions ouvertes .. Est-il possible de dire à Postgresql de fermer ces connexions après un certain temps d'inactivité?

TL; DR

SI vous utilisez une version Postgresql> = 9.2
ALORS utiliser la solution que j'ai proposée

SI vous ne voulez pas écrire de code
ALORS utiliser la solution d’arqnid

32
Stephan

Pour ceux qui sont intéressés, voici la solution que j'ai proposée, inspirée du commentaire de Craig Ringer :

(...) utilise un travail cron à regarder quand la connexion a été active pour la dernière fois (voir pg_stat_activity) et utilise pg_terminate_backend pour tuer les anciens. (...) _

La solution choisie se présente comme ceci:

  • Premièrement, nous passons à Postgresql 9.2.
  • Ensuite, nous planifions un thread pour qu'il s'exécute chaque seconde.
  • Lorsque le thread est exécuté, il recherche les anciennes connexions inactives .
    • Une connexion est considérée comme inactive si son état est soit idle, idle in transaction, idle in transaction (aborted) ou disabled.
    • Une connexion est considérée comme old si son état est resté le même pendant plus de 5 minutes.
  • Il y a des threads supplémentaires qui font la même chose que ci-dessus. Cependant, ces threads se connectent à la base de données avec un utilisateur différent.
  • Nous laissons au moins une connexion ouverte pour toute application connectée à notre base de données. (fonction rank())

Voici la requête SQL exécutée par le thread:

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

Connectez-vous via un proxy comme PgBouncer qui fermera les connexions après server_idle_timeout secondes.

11
araqnid

Si vous utilisez PostgreSQL> = 9.6, la solution est encore plus simple. Supposons que vous souhaitiez supprimer toutes les connexions inactives toutes les 5 minutes, exécutez ce qui suit:

alter system set idle_in_transaction_session_timeout='5min';

Si vous n'avez pas accès en tant que superutilisateur (exemple sur le cloud Azure), essayez:

SET SESSION idle_in_transaction_session_timeout = '5min';

Mais ce dernier ne fonctionnera que pour la session en cours, ce n'est probablement pas ce que vous voulez.

Pour désactiver la fonctionnalité,

alter system set idle_in_transaction_session_timeout=0;

ou

SET SESSION idle_in_transaction_session_timeout = 0;

(au fait, 0 est la valeur par défaut).

Si vous utilisez alter system, vous devez recharger la configuration pour commencer la modification et la modification est persistante. Vous n'avez plus à réexécuter la requête si, par exemple, vous redémarrez le serveur.

Pour vérifier l'état de la fonctionnalité:

show idle_in_transaction_session_timeout;
1
fresko