在Kubernetes中如何让Postgres通过POLLRDHUP实现client_connection_check_interval?
解决PostgreSQL 15在Kubernetes环境下因负载均衡器空闲超时断开连接的问题
问题分析
你在Kubernetes上通过Percona Postgres Operator部署PostgreSQL 15时,遇到服务商托管的负载均衡器(LB)会在180秒后断开空闲连接。配置client_connection_check_interval后未捕获到PG的检查数据包,调整tcp_keepalives...参数也无效,核心原因如下:
client_connection_check_interval依赖Linux内核的POLLHUP/POLLRDHUP扩展事件检测连接状态,但中间的Traefik和LB作为TCP代理会维持与PG的连接,导致PG无法触发该事件,不会主动发送应用层检查包。- TCP保活参数未正确穿透代理层,或者Traefik自身的超时设置与LB冲突,导致保活包未被识别或连接提前被Traefik断开。
可行解决方案
1. 调整TCP保活参数,确保穿透代理层
需要同时配置PostgreSQL服务端和客户端的TCP保活参数,且参数值要小于LB的180秒超时时间,确保保活包能在LB断开连接前触发:
- PostgreSQL服务端配置:在PostgreSQL配置文件(如
postgresql.conf)中添加或修改:
通过Percona Postgres Operator修改配置时,需更新对应的CustomResource,例如在tcp_keepalives_idle = 60 # 连接空闲60秒后启动保活检测 tcp_keepalives_interval = 10 # 每10秒发送一次保活包 tcp_keepalives_count = 3 # 连续3次无响应则断开连接postgres-cluster.yaml的spec.postgres.configuration字段中加入上述参数。 - psql客户端配置:连接时直接指定保活参数:
psql "host=your-pg-host port=5432 dbname=your-db user=your-user options='-c tcp_keepalives_idle=60 -c tcp_keepalives_interval=10 -c tcp_keepalives_count=3'" - Traefik代理层检查:确保Traefik的TCP路由未拦截保活包,可在IngressRouteTCP配置中启用keepAlive传递,同时调整Traefik的空闲超时时间大于LB的180秒:
apiVersion: traefik.containo.us/v1alpha1 kind: IngressRouteTCP metadata: name: postgres-tcp-ingress spec: entryPoints: - postgres routes: - match: HostSNI(`*`) services: - name: percona-postgres-ha port: 5432 timeout: idleTimeout: 240s # 超时时间需大于LB的180秒
2. 应用层心跳替代内核依赖的连接检测
由于client_connection_check_interval无法主动发送应用层检查包,可在客户端侧主动发起心跳查询,避免连接进入空闲状态:
- psql客户端:使用
\watch命令定时执行简单查询,间隔设置为120秒(小于LB的180秒超时):psql -d your-db -h your-pg-host -U your-user -c "SELECT 1;" \watch 120 - 应用程序:在代码中添加定时任务,每隔120秒执行
SELECT 1;或其他轻量查询,维持连接活跃状态。
3. 验证配置效果
修改配置后,可通过tcpdump在客户端或Traefik节点捕获TCP保活包(目标端口5432,包类型为TCP Keep-Alive),或观察连接是否持续超过180秒未被断开,确认配置生效。
内容的提问来源于stack exchange,提问作者Alex F
相关产品推荐
相关产品推荐

