hyperf 3.1.67 的 pool 连接池全量刷新机制是强制丢弃所有现存连接并重建新连接的原子操作,非自动重连;调用 pool::refresh() 会清空 active/idle 连接、释放 socket fd、切断协程绑定,正在执行的请求可能报错需重试,新请求排队等待,超时由 wait_timeout 控制。

Hyperf 3.1.67 中的 Pool 连接池全量刷新机制,不是“自动重连”或“优雅重启”的代名词,而是针对连接泄漏、状态错乱、服务端主动断连后连接残留等顽疾的一次精准外科手术——它强制整个连接池丢弃所有现存连接,重新建立一批全新连接。
Pool::refresh() 触发后发生了什么
调用 Pool::refresh() 不是逐个 ping + close + reconnect,而是原子性地清空当前连接池内部所有连接对象(包括 Active 和 Idle 状态),然后按 min_connections 配置立即重建初始连接集。旧连接的 socket fd 会被底层释放,协程上下文与连接绑定关系彻底切断。
- 不会等待正在使用的连接执行完 SQL 再销毁——正在执行的请求会收到
Connection reset by peer或Broken pipe,需上层捕获并重试 - 新连接全部走完整初始化流程:DNS 解析(若 host 是域名)、TLS 握手、认证、字符集设置、autocommit 初始化
- 刷新过程本身不阻塞请求:新请求会排队等待新连接就绪,超时由
wait_timeout控制
什么时候该手动调用 refresh() 而不是依赖自动机制
Hyperf 默认不自动触发全量刷新,因为代价高、影响面大。你必须在明确感知到连接池已“中毒”时才介入:
- 监控发现
hyperf_db_pool_used_connections持续 ≥max_connections,且hyperf_db_pool_idle_connections长期为 0 —— 表明连接未归还,不是负载高,是泄漏 - 日志中反复出现
PDOException: SQLSTATE[HY000]: General error: 2006 MySQL server has gone away或 PostgreSQL 的server closed the connection unexpectedly - DBA 告知数据库侧执行了主从切换、连接数重置、防火墙策略变更等强干预操作
- 你刚修复了一个已知的连接泄漏 bug(比如某处漏掉
$connection->close()),需要立刻清理存量脏连接
refresh() 在不同数据库驱动下的行为差异
虽然接口统一,但底层实现受驱动协议约束,实际效果有区别:
- MySQL(PDO):
refresh()后新建连接能立即继承原连接的charset、timezone等 session 变量;但事务状态、临时表、用户变量不会迁移 - PostgreSQL(PDO_PGSQL):每个连接独立 session,
refresh()后默认不启用pg_pconnect,所以不会复用 backend PID;但要注意options中若含application_name,新连接会带新值 - Redis(phpredis):连接池刷新后,所有 pipeline、multi-exec 上下文丢失;若使用
RedisCluster,则涉及多个节点连接,刷新是全局生效的 - 注意:gRPC 连接池不支持
refresh()—— 它的生命周期由GRPCConnectionPool自行管理,需调用其CloseAll()+ 重建
容易被忽略的副作用和配置联动
全量刷新不是按下开关就万事大吉,它和几个关键配置强耦合:
-
pool.max_idle_time设得太小(如 5s),会导致连接频繁进出池,放大refresh()触发频率,反而增加 handshake 开销 -
pool.connect_timeout必须大于数据库侧wait_timeout(MySQL)或tcp_keepalives_idle(PostgreSQL),否则刷新时大量连接卡在 handshake 阶段,造成请求堆积 - 若启用了
pool.heartbeat,刷新前心跳检测可能误杀健康连接;建议刷新前临时关闭心跳,刷新完成后再恢复 - Swow 引擎下,刷新瞬间可能触发
Socket is closed(0)报错——这不是失败,而是旧 fd 被回收的正常信号,只要新连接建连成功即可忽略











