如何在PostgreSQL中自动关闭空闲连接?

wlwcrazw  于 2023-05-06  发布在  PostgreSQL
关注(0)|答案(8)|浏览(1027)

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

TL;DR

如果您使用的是PostgreSQL版本〉= 9.2
然后使用the solution I came up with
如果你不想写任何代码
然后使用arqnid's solution
如果你不想写任何代码
并且你使用的是PostgreSQL版本〉= 14
然后使用Laurenz Albe's solution

dphi5xsq

dphi5xsq1#

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

  • (...)使用cron作业来查看连接最后一次活动的时间(参见pg_stat_activity),并使用pg_terminate_backend来删除旧的连接。(...)*

选择的解决方案如下所示:

  • 首先,我们升级到PostgreSQL 9.2。
  • 然后,我们安排一个线程每秒运行一次。
  • 当线程运行时,它会查找任何旧的非活动连接。
  • 如果连接的 * 状态 * 为idleidle in transactionidle in transaction (aborted)disabled,则该连接被视为非活动
  • 如果连接的 * 状态 * 保持不变超过5分钟,则该连接被视为连接。
  • 还有其他线程执行与上述相同的操作。但是,这些线程连接到不同用户的数据库。
  • 我们为连接到数据库的任何应用程序至少保留一个连接。(rank()函数)

这是线程运行的SQL查询:

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
y0u0uwnf

y0u0uwnf2#

如果您使用的是PostgreSQL〉= 9.6,则有一个更简单的解决方案。让我们假设你想每5分钟删除一次所有空闲的连接,只需运行以下命令:

alter system set idle_in_transaction_session_timeout='5min';

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

SET SESSION idle_in_transaction_session_timeout = '5min';

但后者仅适用于当前会话,这很可能不是您想要的。
禁用该功能,

alter system set idle_in_transaction_session_timeout=0;

SET SESSION idle_in_transaction_session_timeout = 0;

(by 0是默认值)。
如果使用alter system,则必须重新加载配置才能开始更改,并且更改是持久性的,例如,如果要重新启动服务器,则不必再重新运行查询。
要检查功能状态,请执行以下操作:

show idle_in_transaction_session_timeout;
inkz8wg9

inkz8wg93#

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

drnojrws

drnojrws4#

从PostgreSQL v14开始,您可以设置idle_session_timeout参数来自动断开空闲的客户端会话。

7cjasjjr

7cjasjjr5#

如果您在PostgreSQL〉= 9.6中使用AWS,则必须执行以下操作:

创建自定义参数组

进入RDS〉Parameter groups〉Create parameter group选择您使用的PSQL版本,将其命名为'customParameters'或其他名称,并添加描述'handle idle connections'。

更改idle_in_transaction_session_timeout值

幸运的是,它将创建默认AWS组的副本,因此您只需调整您认为不适合您的用例的内容。
现在单击新创建的参数组并搜索“idle”。
“idle_in_transaction_session_timeout”的默认值设置为24小时(86400000毫秒)。将这个数字除以24得到小时(3600000),然后您必须再次将3600000除以4,6或12,这取决于您希望超时分别为15,10或5分钟(或等效地乘以分钟数x 60000,因此值300 000为5分钟)。

分配群组

最后,但并非最不重要的是,更改组:
转到RDS,选择您的数据库,然后单击“修改”。
现在,在“数据库选项”下,您将找到“DB参数组”,将其更改为新创建的组。
然后,您可以决定是否要立即应用修改(注意停机时间)。

cgfeq70w

cgfeq70w6#

我有拒绝连接的问题,因为有太多的客户端连接在PostgreSQL 12服务器上(但不是在使用早期9.6和10版本的类似项目上)和Ubuntu 18。
我想知道那些设置

tcp_keepalives_idle 
tcp_keepalives_interval

可能比

idle_in_transaction_session_timeout

idle_in_transaction_session_timeout实际上只关闭失败事务的空闲连接,而不是语句正确终止的非活动连接...文档中说这些套接字级别的设置对Unix域套接字没有影响,但它可以在Ubuntu上工作。

dbf7pr2w

dbf7pr2w7#

到PostgreSQL 13,你可以使用我的扩展pg_timeout

bvn4nwqk

bvn4nwqk8#

以下是使用Docker容器的解决方案:对数据库容器运行以下命令,以找出您拥有的空闲连接数:

echo "SELECT datname, count(*) FROM pg_stat_activity WHERE state = 'idle' GROUP BY datname;" >> query.sql
cat ./query.sql | docker exec -i $name_of_db_container psql -U $pg_user

要终止空闲连接,请对数据库容器运行以下命令:

echo "select pg_terminate_backend(pid) from pg_stat_activity where state = 'idle';" >> query.sql
cat ./query.sql | docker exec -i $name_of_db_container psql -U $pg_user

相关问题