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 withIF 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) ordisabled . - A connection is considered old if its state stayed the same during more than 5 minutes.
-
A connection is considered inactive if its state is either
- 还有其他线程与上面相同。但是,这些线程使用不同的用户连接到数据库。
-
我们为连接到我们数据库的任何应用程序保留至少一个连接。 (
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这样的代理连接,它会在
如果您使用的是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是默认值)。
如果使用
要检查功能状态:
1 | SHOW idle_in_transaction_session_timeout; |