Y a-t-il un délai pour les connexions PostgreSQL inactives?

94
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             

J'en vois beaucoup. Nous essayons de réparer notre fuite de connexion. Mais en attendant, nous voulons définir un délai d'expiration pour ces connexions inactives, peut-être jusqu'à 5 minutes maximum.

user1012451
la source
comment vous connectez-vous à la base de données? socketTimeout est peut-être ce que vous recherchez.
Doon
Nous avons cette ancienne application Web Pylons et nous avons utilisé SQLAlchemy, mais apparemment, nous ne l'avons pas utilisée correctement. Je ne m'en souviens pas. Nous essayons de réparer la fuite. socketTimeoutà partir de la documentation, il ressemble à cela ferme la connexion à la base de données, entièrement. J'essaye de fermer chaque inactif, et le compteur démarre dès que la connexion est établie.
user1012451
@ user1012451 Quand vous dites "fermer chaque inactif" - voulez-vous dire mettre fin aux <IDLE> in transactionsessions, laisser la session en cours d'exécution mais en <IDLE>état? En d'autres termes, terminer la transaction mais pas la session? (Vote négatif: question peu claire)
Craig Ringer
@CraigRinger après un certain temps, nous atteignons la connexion client maximale. Pour résoudre cela, nous devons redémarrer l'application Web, ce qui oblige également à redémarrer postgresql. Cela efface toute connexion. Quand nous les voyons idlepour toujours, nous nous demandons si nous pourrions définir un délai d'expiration pour chaque connexion / session (honnêtement, je ne connais pas la terminologie correcte, désolé). Si une transaction prend 5 minutes pour une application Web normale, quelque chose ne va pas ...
user1012451

Réponses:

118

Il semble que vous ayez une fuite de connexion dans votre application car elle ne parvient pas à fermer les connexions groupées . Vous ne rencontrez pas de problèmes uniquement avec les <idle> in transactionsessions, mais avec trop de connexions en général.

Tuer les connexions n'est pas la bonne réponse pour cela, mais c'est une solution de contournement temporaire OK.

Plutôt que de redémarrer PostgreSQL pour démarrer toutes les autres connexions à partir d'une base de données PostgreSQL, consultez: Comment détacher tous les autres utilisateurs d'une base de données postgres? et Comment supprimer une base de données PostgreSQL s'il y a des connexions actives? . Ce dernier montre une meilleure requête.

Pour définir les délais d'expiration, comme @Doon l'a suggéré, consultez Comment fermer automatiquement les connexions inactives dans PostgreSQL? , qui vous conseille d'utiliser PgBouncer pour proxy pour PostgreSQL et gérer les connexions inactives. C'est une très bonne idée si vous avez une application boguée qui perd de toute façon des connexions; Je recommande fortement de configurer PgBouncer.

Un keepalive TCP ne fera pas le travail ici, car l'application est toujours connectée et vivante, elle ne devrait tout simplement pas l'être.

Dans PostgreSQL 9.2 et versions ultérieures, vous pouvez utiliser la nouvelle state_changecolonne d'horodatage et le statechamp de pg_stat_activitypour implémenter un outil de récupération de connexion inactif. Demandez à une tâche cron d'exécuter quelque chose comme ceci:

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;

Dans les anciennes versions, vous devez implémenter des schémas complexes qui permettent de suivre le moment où la connexion est devenue inactive. Ne pas déranger; utilisez simplement pgbouncer.

Craig Ringer
la source
4
Bien, mais cela tuera les autres backends PgAdmin. Utiliser une condition supplémentaire nom_application = ''
Andrew Selivanov
1
Puis-je exécuter pg_terminate_backend si j'utilise pgbouncer?
Henley Chiu
@HenleyChiu Je ne vois pas pourquoi, même si je n'ai pas spécifiquement vérifié.
Craig Ringer
1
L'exécution de cela semble avoir tué mon processus d'expéditeur WAL
Joseph Persie
@CraigRinger même une connexion psql est considérée comme une connexion inactive. Et pourquoi doit-on fermer la connexion inactive en premier lieu. J'ai un code de longue durée qui établit une connexion avec pg, effectue une opération dml, puis attend le message sur la file d'attente, puis effectue une autre opération dml.Maintenant pendant cette période, c'est-à-dire pendant qu'il attend sur la file d'attente (pour le message) comme mentionné ci-dessus même alors, la connexion avec les postges est idle. pourquoi devrais-je le fermer.
Viren
72

Dans PostgreSQL 9.6, il existe une nouvelle option idle_in_transaction_session_timeoutqui devrait accomplir ce que vous décrivez. Vous pouvez le définir à l'aide de la SETcommande, par exemple:

SET SESSION idle_in_transaction_session_timeout = '5min';
Shosti
la source
1
Cela craint de devoir demander quelque chose d'aussi simple, mais je suis tout nouveau dans les bases de données en général - Pourriez-vous s'il vous plaît donner un exemple très basique de la façon d'utiliser cette fonction?
sg
Quelque chose comme ça dans les versions précédentes de PostgreSQL ??
sdsc81
Non, quelque chose qui ressemble aux autres réponses est requis pour les versions précédentes.
shosti
Avez-vous besoin de définir ce paramètre à chaque redémarrage de la base de données? Ou après vous avez fait une fois que vous pouvez oublier? Merci
fresko
5
SET SESSIONest juste pour la session en cours (il reviendra à la valeur par défaut une fois que vous ouvrirez une nouvelle connexion). Vous pouvez également définir des paramètres de configuration au niveau de la base de données en utilisant, par exemple ALTER DATABASE SET idle_in_transaction_session_timeout = '5min', ou en utilisant des fichiers de configuration (voir postgresql.org/docs/current/static/config-setting.html ).
shosti
22

Dans PostgreSQL 9.1, les connexions inactives avec la requête suivante. Cela m'a aidé à éviter la situation qui justifiait le redémarrage de la base de données. Cela se produit principalement avec les connexions JDBC ouvertes et non fermées correctement.

SELECT
   pg_terminate_backend(procpid)
FROM
   pg_stat_activity
WHERE
   current_query = '<IDLE>'
AND
   now() - query_start > '00:10:00';
sramay
la source
1
pg_terminate_backend est depuis 8.4
Andrew Banks
8

si vous utilisez postgresql 9.6+, vous pouvez définir dans votre postgresql.conf

idle_in_transaction_session_timeout = 30000 (msec)

Bertrand David
la source
0

Une solution de contournement possible qui permet d'activer le délai d'expiration de session de base de données sans tâche planifiée externe consiste à utiliser l'extension pg_timeout que j'ai développée.

pifor
la source