关于超时:如何自动关闭PostgreSQL中的空闲连接?

How to close idle connections in PostgreSQL automatically?

有些客户端连接到我们的postgresql数据库,但保持连接打开。
是否有可能告诉Postgresql在一定量的不活动后关闭这些连接?

TL; DR

IF you're using a Postgresql version >= 9.2
THEN use the solution I came up with

IF you don't want to write any code
THEN use arqnid's solution


对于那些感兴趣的人,这是我提出的解决方案,灵感来自Craig Ringer的评论:

(...) use a cron job to look at when the connection was last active (see pg_stat_activity) and use pg_terminate_backend to kill old ones.(...)

选择的解决方案如下:

  • 首先,我们升级到Postgresql 9.2。
  • 然后,我们安排一个线程每秒运行一次。
  • 当线程运行时,它会查找任何旧的非活动连接。

    • A connection is considered inactive if its state is either idle, idle in transaction, idle in transaction (aborted) or disabled.
    • A connection is considered old if its state stayed the same during more than 5 minutes.
  • 还有其他线程与上面相同。但是,这些线程使用不同的用户连接到数据库。
  • 我们为连接到我们数据库的任何应用程序保留至少一个连接。 (rank()功能)

这是线程运行的SQL查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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


通过像PgBouncer这样的代理连接,它会在server_idle_timeout秒后关闭连接。


如果您使用的是PostgreSQL> = 9.6,则可以使用更简单的解决方案。假设您希望每5分钟删除所有空闲连接,只需运行以下命令:

1
ALTER system SET idle_in_transaction_session_timeout='5min';

如果您没有超级用户访问权限(Azure云上的示例),请尝试:

1
SET SESSION idle_in_transaction_session_timeout = '5min';

但后者只适用于本届会议,很可能不是你想要的。

要禁用此功能,

1
ALTER system SET idle_in_transaction_session_timeout=0;

要么

1
SET SESSION idle_in_transaction_session_timeout = 0;

(顺便说一下,0是默认值)。

如果使用alter system,则必须重新加载配置以启动更改并且更改是持久的,例如,如果您将重新启动服务器,则不必再重新运行查询。

要检查功能状态:

1
SHOW idle_in_transaction_session_timeout;