网络断开或强制重启服务器时Postgres的Socket连接未关闭
我正在使用 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这个选项的系统上有效;在其他系统上,它就没有任何作用。
换句话说,如果你的系统不支持这个功能,那就没什么用,正常的超时规则会照常适用。