网络断开或强制重启服务器时Postgres的Socket连接未关闭

0 投票
1 回答
1021 浏览
提问于 2025-04-17 17:02

我正在使用 sqlalchemy 和 postgresql 建立连接,并执行简单的命令。

>>> from sqlalchemy import create_engine
>>> c = create_engine('postgres://myuser@myremoteserver/mydb?keepalives_idle=4&keepalives_interval=1&keepalives_count=5')
>>> c.execute('select 1').scalar()
1

一切运行得很好。

在建立连接后,当你执行查询时,它会为 postgres 服务器创建一个套接字,在这个例子中,它会连接到 myremoteserver。我们可以用 unix 的 ss 命令来检查这个套接字。(你也可以使用 netstat。)

[root@myclient ~]# ss -torp | grep python
ESTAB      0      0            192.168.1.15:43471       myremoteserver:postgres  timer:(keepalive,1.319ms,0) users:(("python",4074,3))

如果网络断了或者 postgres 服务器的机器崩溃了,在建立连接后。

>>> c = create_engine('postgres://myuser@myremoteserver/mydb?keepalives_idle=4&keepalives_interval=1&keepalives_count=5')

(你可以在 myremoteserver 上执行 ifdown eth0 来断开网络。)

那么在尝试连接服务器 5 次后,它会关闭连接。

[root@myclient ~]# ss -torp | grep python
ESTAB      0      0            192.168.1.15:43471       myremoteserver:postgres  timer:(keepalive,1.319ms,0) users:(("python",4074,3))
[root@myclient ~]# ss -torp | grep python
ESTAB      0      0            192.168.1.15:43471       myremoteserver:postgres  timer:(keepalive,738ms,0) users:(("python",4074,3))
[root@myclient ~]# ss -torp | grep python
ESTAB      0      0            192.168.1.15:43471       myremoteserver:postgres  timer:(keepalive,2.720ms,0) users:(("python",4074,3))
[root@myclient ~]# ss -torp | grep python
ESTAB      0      0            192.168.1.15:43471       myremoteserver:postgres  timer:(keepalive,788ms,2) users:(("python",4074,3))
[root@myclient ~]# ss -torp | grep python
ESTAB      0      0            192.168.1.15:43471       myremoteserver:postgres  timer:(keepalive,191ms,4) users:(("python",4074,3))
[root@myclient ~]# ss -torp | grep python
[root@myclient ~]# ss -torp | grep python

这是我们在连接字符串中设置的连接行为。

如果在套接字关闭和服务器崩溃之间执行查询,就会出现问题。

# do ifdown eth0 on postgres server to break the network connection.
# execute query before socket close.
>>> c.execute('select 1').scalar()

现在如果你检查套接字,

[root@myclient ~]# ss -torp | grep python
ESTAB      0      74           192.168.1.15:43471       myremoteserver:postgres  timer:(on,1.602ms,3) users:(("python",3098,7))
[root@myclient ~]# ss -torp | grep python
ESTAB      0      74           192.168.1.15:43471       myremoteserver:postgres  timer:(on,585ms,3) users:(("python",3098,7))
[root@myclient ~]# ss -torp | grep python
ESTAB      0      74           192.168.1.15:43471       myremoteserver:postgres  timer:(on,2.833ms,4) users:(("python",3098,7))
[root@myclient ~]# ss -torp | grep python
ESTAB      0      74           192.168.1.15:43471       myremoteserver:postgres  timer:(on,1.851ms,4) users:(("python",3098,7))
[root@myclient ~]# ss -torp | grep python
ESTAB      0      74           192.168.1.15:43471       myremoteserver:postgres  timer:(on,808ms,4) users:(("python",3098,7))
[root@myclient ~]# ss -torp | grep python
ESTAB      0      74           192.168.1.15:43471       myremoteserver:postgres  timer:(on,5.393ms,5) users:(("python",3098,7))
[root@myclient ~]# ss -torp | grep python
ESTAB      0      74           192.168.1.15:43471       myremoteserver:postgres  timer:(on,3.846ms,5) users:(("python",3098,7))
.................
.................
.................
[root@myclient ~]# ss -torp | grep python
ESTAB      0      74           192.168.1.15:43471       myremoteserver:postgres  timer:(on,5.268ms,72) users:(("python",3098,7))
[root@myclient ~]# ss -torp | grep python
ESTAB      0      74           192.168.1.15:43471       myremoteserver:postgres  timer:(on,4.804ms,254) users:(("python",3098,7))

根据连接字符串,套接字应该在尝试 5 次后关闭。但我不知道为什么它会尝试超过 5 次,甚至达到 254 次。

我需要设置什么才能在执行查询时,即使在服务器崩溃和客户端关闭套接字之间,也能在 5 次尝试后关闭套接字。

注意:keepalives_idle、keepalives_interval 和 keepalives_count 是用来设置 TCP 连接中的 keepalive 参数的。

1 个回答

1

来自PostgreSQL文档:

这个设置控制在客户端和服务器之间的连接被认为“死掉”之前,可以丢失多少个TCP保持活动信号(keepalive)。如果设置为零,就会使用系统的默认值。如果通过Unix域套接字连接,或者保持活动信号被禁用,这个参数就会被忽略。这个设置只在支持TCP_KEEPCNT这个选项的系统上有效;在其他系统上,它就没有任何作用。

换句话说,如果你的系统不支持这个功能,那就没什么用,正常的超时规则会照常适用。

撰写回答