¿Existe un tiempo de espera para las conexiones inactivas de PostgreSQL?

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             

Veo muchos de ellos. Estamos tratando de arreglar nuestra fuga de conexión. Pero mientras tanto, queremos establecer un tiempo de espera para estas conexiones inactivas, tal vez como máximo de 5 minutos.

usuario1012451
fuente
¿cómo te conectas a la base de datos? socketTimeout podría ser lo que estás buscando.
Doon
Tenemos esta aplicación web heredada de Pylons y usamos SQLAlchemy, pero aparentemente no la usamos correctamente. No recuerdo Estamos intentando arreglar la fuga. socketTimeoutdesde el documento parece que esto cierra la conexión a la base de datos, por completo. Estoy tratando de cerrar cada inactividad y el contador comienza tan pronto como se establece la conexión.
user1012451
@ user1012451 Cuando dices "cerrar cada inactivo", ¿te refieres a terminar <IDLE> in transactionsesiones y dejar la sesión en ejecución pero en <IDLE>estado? En otras palabras, ¿terminar la transacción pero no la sesión? (Votación en contra: pregunta poco clara)
Craig Ringer
@CraigRinger después de un tiempo, alcanzamos la conexión máxima de cliente. Para solucionar eso, debemos reiniciar la aplicación web, lo que obliga a reiniciar postgresql también. Eso borra todas las conexiones. Cuando vemos estos idlepara siempre, preguntamos si podemos establecer un tiempo de espera en cada conexión / sesión (sinceramente, no conozco la terminología correcta, lo siento). Si una transacción toma 5 minutos para una aplicación web normal, algo debe estar mal ....
user1012451

Respuestas:

118

Parece que tiene una fuga de conexión en su aplicación porque no cierra las conexiones agrupadas . No tiene problemas solo con las <idle> in transactionsesiones, sino con demasiadas conexiones en general.

Matar conexiones no es la respuesta correcta para eso, pero es una solución temporal aceptable.

En lugar de reiniciar PostgreSQL para arrancar todas las demás conexiones desde una base de datos PostgreSQL, consulte: ¿Cómo desconecto a todos los demás usuarios de una base de datos de Postgres? y ¿Cómo eliminar una base de datos PostgreSQL si hay conexiones activas a ella? . Este último muestra una mejor consulta.

Para configurar tiempos de espera, como sugirió @Doon, consulte ¿Cómo cerrar conexiones inactivas en PostgreSQL automáticamente? , que le aconseja utilizar PgBouncer como proxy para PostgreSQL y administrar las conexiones inactivas. Esta es una muy buena idea si tiene una aplicación con errores que de todos modos pierde conexiones; Recomiendo encarecidamente configurar PgBouncer.

Un keepalive de TCP no hará el trabajo aquí, porque la aplicación todavía está conectada y viva, simplemente no debería estarlo.

En PostgreSQL 9.2 y superior, puede usar la nueva state_changecolumna de marca de tiempo y el statecampo de pg_stat_activitypara implementar un reaper de conexión inactiva. Haga que un trabajo cron ejecute algo como esto:

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;

En versiones anteriores, debe implementar esquemas complicados que realicen un seguimiento de cuándo la conexión quedó inactiva. No molestar; solo usa pgbouncer.

Craig Ringer
fuente
4
Bien, pero matará a otros backends de PgAdmin. Utilice la condición adicional application_name = ''
Andrew Selivanov
1
¿Puedo ejecutar pg_terminate_backend si estoy usando pgbouncer?
Henley Chiu
@HenleyChiu No veo por qué no, aunque no lo he comprobado específicamente.
Craig Ringer
1
Ejecutar esto parece haber matado mi proceso de remitente WAL
Joseph Persie
@CraigRinger incluso una conexión psql se considera una conexión inactiva. Y por qué uno tiene que cerrar la conexión inactiva en primer lugar. Tengo un código de ejecución prolongada que establece una conexión con pg, realizo una operación dml y luego espero el mensaje en la cola y luego realizo más operaciones dml.Ahora, durante ese período, es decir, mientras está esperando en la cola (para el mensaje) como se mencionó anteriormente incluso entonces la conexión con postges es idle. ¿Por qué debería cerrarlo?
Viren
72

En PostgreSQL 9.6, hay una nueva opción idle_in_transaction_session_timeoutque debería lograr lo que describe. Puede configurarlo usando el SETcomando, por ejemplo:

SET SESSION idle_in_transaction_session_timeout = '5min';
shosti
fuente
1
Es una mierda tener que preguntar algo tan simple, pero soy nuevo en las bases de datos en general. ¿Podría dar un ejemplo muy básico de cómo usar esta función?
sg
¿Algo como esto en versiones anteriores de PostgreSQL?
sdsc81
No, se requiere algo similar a las otras respuestas para versiones anteriores.
Shosti
¿Necesita establecer este parámetro en cada reinicio de la base de datos? ¿O después de que lo hizo una vez que puede olvidarse? Gracias
fresko
5
SET SESSIONes solo para la sesión actual (volverá al valor predeterminado una vez que abra una nueva conexión). También puede establecer parámetros de configuración a nivel de base de datos usando ALTER DATABASE SET idle_in_transaction_session_timeout = '5min', por ejemplo , o usando archivos de configuración (consulte postgresql.org/docs/current/static/config-setting.html ).
shosti
22

En PostgreSQL 9.1, las conexiones inactivas con la siguiente consulta. Me ayudó a evitar la situación que justificaba reiniciar la base de datos. Esto ocurre principalmente con conexiones JDBC abiertas y no cerradas correctamente.

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

si está utilizando postgresql 9.6+, entonces en su postgresql.conf puede configurar

idle_in_transaction_session_timeout = 30000 (mseg)

Bertrand David
fuente
0

Una posible solución que permite habilitar el tiempo de espera de la sesión de la base de datos sin una tarea programada externa es usar la extensión pg_timeout que he desarrollado.

pifor
fuente