go标准库database/sql连接池不支持自动重连,断线后首次使用报错;pgxpool通过ping检测、连接回收和定期清理三层机制实现可靠恢复,go-redis则在命令执行失败时按指数退避自动重连。

Go语言标准库的database/sql连接池本身不支持自动重连;断线后首次使用会报错,后续请求可能成功(取决于驱动实现),但无法保证连接有效性。真正可靠的断线恢复必须依赖具体数据库驱动的扩展能力或上层封装逻辑。
pgxpool 的健康检查与连接回收机制
pgxpool 是 PostgreSQL 最主流的 Go 驱动连接池,它通过三层机制应对断线:
- 从池中获取连接时:若空闲时间超过
MaxConnIdleTime(默认 30 分钟)或自定义的ShouldPing条件满足,会先执行一次Ping()检测,失败则丢弃该连接并新建 - 连接归还到池时:检查是否超时
MaxConnLifetime(默认 1 小时)或MaxConnIdleTime,超时则直接关闭 - 后台定期清理:每 30 秒(可配)扫描过期连接并关闭,避免堆积无效连接
注意:Ping() 是轻量级 SQL 查询(SELECT 1),不是 TCP 层心跳;它能发现服务端 kill、事务中断、连接被 proxy 清理等场景,但无法覆盖网络中间设备静默丢包(此时 Ping() 可能卡住,需靠 Context 超时兜底)。
redis-go 客户端的重连策略差异
不同 Redis 客户端对重连的支持程度差别很大:
-
github.com/go-redis/redis/v9:默认启用自动重连,失败后按指数退避重试(初始 100ms,上限 5s),但仅对网络类错误生效;认证失败、命令语法错误等业务错误不会重连 -
gopkg.in/redis.v5(已归档):无内置重连,需手动包装Do()或监听err != nil后重建*redis.Client - 自建连接池(如
sync.Pool+net.Conn):完全无重连能力,必须自行实现拨号循环、错误分类、conn.Close()清理和退避逻辑
关键点:go-redis 的重连只发生在命令执行阶段(即 client.Get(ctx, key).Result() 报错时),不是在连接获取时;因此仍可能出现“拿到连接→立刻失效→命令失败→触发重连”的延迟感知。
自定义连接池重连必须处理的三个泄漏点
手动实现带重连的连接池(如封装 net.Conn 或 WebSocket)时,以下三点不处理就会快速耗尽文件描述符或 goroutine:
- 每次重连前必须显式调用
conn.Close()(如果conn != nil),否则旧连接 fd 不释放 - 读写 goroutine 必须监听
ctx.Done()或独立的reconnectCh,不能靠for { ... time.Sleep() }硬循环阻塞等待 - 心跳定时器(如
time.Ticker)必须在重连前Stop(),否则旧 timer 会持续向已关闭的conn发送PingMessage,导致 panic
最易被忽略的是:WebSocket 重连后,旧的写 channel 若未替换,新 goroutine 往已关闭的 channel 发消息会直接 panic —— 这个问题在线上环境往往表现为偶发崩溃,难以复现。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











