2012-09-12 221 views
26

Algunos clientes se conectan a nuestra base de datos postgresql pero dejan las conexiones abiertas. ¿Es posible decirle a Postgresql que cierre esas conexiones después de una cierta cantidad de inactividad?¿Cómo cerrar conexiones inactivas en PostgreSQL automáticamente?

TL; DR

si usted está utilizando una versión de PostgreSQL> = 9.2
utilizar ENTONCES the solution I came up with

SI usted no desea escribir ningún código
luego usar arqnid's solution

+2

Se podría utilizar una tarea programada para mirar cuando la conexión estuvo activo (véase 'pg_stat_activity') y el uso de' pg_terminate_backend' para matar a los viejos. Expresado fácilmente en una consulta simple. Sin embargo, no estoy seguro de si 'pg_terminate_backend' estaba disponible en el bonito y antiguo 8.3. –

Respuesta

27

Para aquellos que estén interesados, aquí está la solución que se me ocurrió, inspirado en Craig Ringer 's comentario:

(...) utilizar una tarea programada para mirar cuando la conexión fue el último activa (ver pg_stat_activity) y utilizar pg_terminate_backend para matar a los viejos (...)

La solución elegida se reduce de esta manera:.

  • Primero, actualizamos a Postgresql 9.2.
  • Luego, programamos un hilo para que se ejecute cada segundo.
  • Cuando se ejecuta el subproceso, busca cualquier conexión inactiva anterior.
    • Una conexión se considera inactivo si su estado es o bien idle, idle in transaction, idle in transaction (aborted) o disabled.
    • Se considera que una conexión es anterior si su último estado ha cambiado durante más de 5 minutos.
  • Hay subprocesos adicionales que hacen lo mismo que el anterior. Sin embargo, esos hilos se conectan a la base de datos con diferentes usuarios.
  • Dejamos al menos una conexión abierta para cualquier aplicación conectada a nuestra base de datos. (rank() función)

Ésta es la consulta SQL a cargo de la rosca:

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 
+0

Finalmente, nos movimos a Postgresql 9.2 para obtener una ventaja de 'pg_terminate_backend'. Usamos un trabajo como cron para invocar periódicamente 'pg_terminate_backend'. – Stephan

+0

¿Puedes publicar un script que usas? – Andrus

+0

@Andrus Vea la actualización en mi respuesta. – Stephan

10

Conéctese a través de un proxy como PgBouncer que cerrará las conexiones después de server_idle_timeout segundos.

+0

puede pg pool II hacer lo mismo? – wolf97084

+0

@ wolf97084 Ver esta respuesta: http: // stackoverflow.com/a/30769511/363573 – Stephan

+0

@Stephan ¡Gracias! Extrañaría la respuesta si no me hubieras etiquetado en el comentario. – wolf97084

Cuestiones relacionadas