postgresql-tcp_keepalive参数相关


TCP KEEPALIVE FOR A BETTER POSTGRESQL EXPERIENCE【译】

如果您听说过 TCP keepalive 但不确定那是什么,请继续阅读。如果您曾经对以下错误消息感到惊讶:

  • server closed the connection unexpectedly
  • SSL SYSCALL error: EOF detected
  • unexpected EOF on client connection
  • could not receive data from client: Connection reset by peer

那么这篇文章会有用

连接断开的原因

连接断开有几个可能的原因:

数据库服务器崩溃

上面列表中的前两条消息可能是因为 PostgreSQL 服务器的问题。如果服务器因任何原因崩溃,您将看到类似的消息。要调查是否存在服务器问题,您应该首先查看 PostgreSQL 日志,看看是否可以找到匹配的崩溃报告。

我们不会在下面讨论这种情况,因为它不是网络问题。

客户端放弃的连接

如果客户端在没有正确关闭数据库连接的情况下退出,当用网络socket通信时,服务器会收到文件结束或错误。使用v14 中引入的新会话统计信息,您可以在pg_stat_database.sessions_abandoned字段中看到数据库断开连接的信息。

例如,如果应用程序服务器出现故障并重新启动,它通常不会关闭与数据库服务器的连接。这并不奇怪,当服务器试图向客户端发送数据时,数据库服务器会迅速检测到它。但是如果数据库会话处于空闲状态,则服务器进程正在等待客户端发送下一条语句(可以看到pg_stat_activity中的wait_event“ 是ClientRead” )。然后服务器不会立即发现客户端不再存在!这种挥之不去的后端进程占用一个进程槽,并可能导致您超过max_connections.

PostgreSQL v14 引入了一个新参数idle_session_timeout,它会在一段时间后关闭空闲连接。但这也会终止“健康”的空闲连接,因此这不是一个很好的解决方案。TCP keepalive 为这个问题提供了更好的解决方案。

网络组件导致的连接关闭

有时数据库连接的两端都会遇到同样的问题:每一端都看到另一端“挂断了它们”。在这种情况下,问题出在数据库客户端和服务器之间。

如果存在真正的连接问题,网络连接可能会断开。您无法在软件级别上更改它。但很多时候,断开连接是由防火墙或路由器的配置方式引起的。网络组件可能必须“记住”每个打开连接的状态,而用于此的资源是有限的。因此,“忘记”并丢弃已闲置较长时间的连接似乎是权宜之计。

由于当今的许多 TCP 流量都是通过 HTTP 进行的,而且 HTTP 是无状态的,所以这通常不是问题。如果您的 HTTP 连接中断,您只需为下一个请求建立一个新连接,这并不昂贵。但数据库不同:

  • 建立数据库连接的成本很高
  • 数据库连接不是无状态的;例如,在关闭连接的情况下,您会丢失打开的事务、临时表和准备好的语句
  • 数据库会话空闲较长时间正常的,例如,如果您正在使用连接池,或者当客户端正在等待长时间运行的分析查询的结果时

这就是 TCP keepalive 派上用场的地方,它可以作为保持空闲连接打开的一种方式。

什么是 TCP keepalive?

Keepalive 是 TCP 协议的一项功能。当您在TCP network socket中使用SO_KEEPALIVE选项时,一旦socket idle,计时器就会开始运行。当**keepalive idle time* *到期,并且socket上没有进一步的活动时,kernel内核将向通信伙伴发送一个“keepalive数据包”。如果对方回答,则认为连接良好,计时器再次开始运行。

如果没有应答,内核等一个keepalive间隔(keepalive interval ),再发送另一个keepalive packet探活。

重复此过程,直到发送的数据包量达到 keepalive count。如果之后(还是无应答),连接就被认为是结束了,再尝试使用network socket就会报错。

请注意,发送keepalive消息的是操作系统内核,而不是应用程序(数据库服务器或客户端)。应用程序不知道此过程。

TCP keepalive 有两个目的:

  • 防止网络连接空闲
  • 检测另一个通信端是否在没有关闭网络连接的情况下断开
    (“keepalive”这个名字描述得不太好——“detectdead”更重要)。

TCP 保活默认设置

keepalive 参数的默认值因操作系统而异。在 Linux 和 Windows 上,默认值为:

  • keepalive 空闲时间:Linux 和 Windows 上均为 2 小时
  • keepalive 间隔:Linux 上 75 秒,Windows 上 1 秒
  • keepalive 计数:Linux 上为 9,Windows 上为 10(此值在 Windows 上无法更改)

我没有找到 MacOS 的默认设置。

使用 TCP keepalive 使空闲的数据库会话保持活动状态

为了防止防火墙和路由器关闭空闲连接,我们需要一个低得多的 keepalive 空闲时间设置。这样在连接关闭之前就能发送keepalive数据包。这能骗到网络组件相信连接不是空闲的,即使数据库客户端和服务器都没有发送任何数据。

在这情况下,keepalive count and keepalive interval无关。我们所需要的只是足够早地发送第一个keepalive packet。

使用 TCP keepalive 检测死连接

在这情况下,减少 keepalive 空闲时间通常是不够的。如果服务器以 75 秒的间隔发送 9 个 keepalive 数据包,则需要 10 多分钟才能检测到死连接。因此,我们还将减少保活计数或保活间隔,或两者兼而有之——如本例所示。

这个难题还缺少一块:即使操作系统检测到网络连接断开,数据库服务器也不会注意到,除非它尝试使用network socket。如果它正在等待来自客户端的请求,那将立即发生。但是,如果服务器正忙于执行一个长时间运行的 SQL 语句,它不会注意到死连接,直到查询完成并尝试将结果发送回客户端!为了防止这种情况发生,PostgreSQL v14 引入了新参数client_connection_check_interval,目前仅在 Linux 上支持。设置此参数会导致服务器定期“轮询”套接字,即使它还没有要发送的内容。这样,它可以检测到关闭的连接并中断 SQL 语句的执行。

在 PostgreSQL 服务器上设置 TCP keepalive 参数

PostgreSQL 服务器总是设置SO_KEEPALIVETCP 套接字以检测断开的连接,但默认的两小时空闲超时非常长。

您可以设置配置参数tcp_keepalives_idletcp_keepalives_interval以及tcp_keepalives_count(Windows 不支持最后一个)来更改所有服务器套接字的设置。

这是为所有数据库连接配置 TCP keepalive 的最便捷方式,无论使用何种客户端。

在 PostgreSQL 客户端上设置 TCP keepalive 参数

PostgreSQL 客户端共享库libpq具有连接参数keepalives_idlekeepalives_interval并且keepalives_count(同样,Windows 不支持后者)在客户端配置 keepalive。

这些参数可以在 PostgreSQL 连接字符串中与所有与 链接的客户端接口一起使用libpq,例如,Psycopg 或 PHP。

PostgreSQL JDBC驱动,没有使用libpq,只有连接参数tcpKeepAlive开启TCP keepalive(默认关闭),没有参数配置keepalive空闲时间和其他keepalive设置。

在操作系统上设置 TCP keepalive 参数

您可以更改所有 TCP 连接的操作系统默认值,而不是专门为 PostgreSQL 连接配置 keepalive 设置 - 如果您使用的 PostgreSQL 客户端应用程序不允许您设置 keepalive 连接参数,这可能很有用。

在 Linux 上,这是通过编辑/etc/sysctl.conf文件来完成的:

# detect dead connections after 70 seconds``net.ipv4.tcp_keepalive_time = 60``net.ipv4.tcp_keepalive_intvl = 5``net.ipv4.tcp_keepalive_probes = 3

要在不重新启动机器的情况下激活设置,请运行

sysctl -p

在 Windows 上,您可以通过添加以下注册表项来更改 TCP keepalive 设置:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters\KeepAliveTime``HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters\KeepAliveInterval

如上所述,keepalive 探测的数量没有设置,硬编码为 10。注册表项的类型必须为DWORD,并且值以毫秒而不是秒为单位。

更改这些键后,重新启动 Windows 以激活它们。

结论

配置 TCP keepalive 可以通过保持空闲数据库连接打开或通过及时检测断开连接来改善您的 PostgreSQL 体验。您可以在 PostgreSQL 客户端、服务器或操作系统上配置 keepalive。

除了配置 keepalive 之外,设置新参数client_connection_check_interval以在客户端放弃会话时取消长时间运行的查询。

【原文】

https://www.cybertec-postgresql.com/en/tcp-keepalive-for-a-better-postgresql-experience/

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

我的环境上默认tcp_keepalives_idle=60,tcp_keepalives_interval=10,tcp_keepalives_count=10

即60s+10*10=160s之后会断开连接
报错could not receive data from client: Connection reset by peer,尝试加大tcp_keepalives_idle


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM