Hyperf 的 pool.heartbeat 默认为-1(禁用),须设为正整数(如30)才生效;max_idle_time必须严格小于MySQL的wait_timeout(建议设为wait_timeout−30),且heartbeat应≤max_idle_time(推荐floor(max_idle_time/2))。

Hyperf 的 pool.heartbeat 默认不生效,必须显式配正整数
很多人在 config/autoload/db.php 里写了 'heartbeat' => true 或 'heartbeat' => 30,结果日志里没看到心跳动作,2006 错误照旧。根本原因是:heartbeat 默认值是 -1(禁用),设成 true 不会被识别为有效数值,Hyperf 直接忽略;只有设为正整数(如 30)才启用后台空闲连接探测。
-
heartbeat: -1:完全关闭检测,靠取连接时临时PING(只做一次,不防“睡过头”) -
heartbeat: 0或false或true:配置无效,等同于-1 -
heartbeat: 30:每 30 秒由后台线程扫描空闲连接,发PING探活
max_idle_time 必须严格小于 MySQL 的 wait_timeout
这是最容易配错、也最致命的一环。如果 max_idle_time ≥ MySQL 的 wait_timeout(比如 MySQL 是 300 秒,你设了 300 或 360),那连接在池里“躺平”到被 MySQL 主动断开后才回收,取出时必然报 MySQL server has gone away。
- 先查 MySQL 实际值:
SHOW VARIABLES LIKE 'wait_timeout';(注意:不是interactive_timeout) -
max_idle_time建议设为wait_timeout - 30(留出网络延迟和调度偏差缓冲) - 例如 MySQL
wait_timeout = 300→max_idle_time = 270是安全上限 - 若设
max_idle_time = 300,哪怕heartbeat = 150,也救不回第 301 秒还在池里的连接
heartbeat 和 max_idle_time 必须满足大小关系
心跳不是独立运行的定时器,它依赖空闲连接回收机制触发检测逻辑。如果 heartbeat ≥ max_idle_time,意味着连接还没等到心跳检查就被回收了,等于白配。
- 推荐公式:
heartbeat = floor(max_idle_time / 2)(如max_idle_time = 270→heartbeat = 135) - 避免设太小:
heartbeat = 5会导致每秒多次PING,对 MySQL 是无效压力 - 避免设太大:
heartbeat = 600在max_idle_time = 270下毫无意义 - 注意单位:全部是秒,浮点数(如
135.0)也可,但整数更清晰
别漏掉协同参数:wait_timeout 和 ATTR_TIMEOUT
光靠心跳只能“发现尸体”,还得配合其他参数防止“用尸体干活”和“卡死等新尸”。这几个值不在同一配置层级,容易漏调。
-
pool.wait_timeout(连接池层面):设为3.0~5.0,避免协程无限等待空闲连接 -
options.ATTR_TIMEOUT(PDO 层面):设为3,单条查询超时就中断,防止慢查询拖垮连接状态 -
min_connections别设0:冷启动时全重建连接,首请求延迟高;建议 ≥2 - 验证是否生效:不是看日志有没有 “heartbeat” 字样,而是观察
SHOW PROCESSLIST中空闲连接存活时间是否稳定在max_idle_time附近
实际运行中,heartbeat 的有效性高度依赖 MySQL 驱动是否真正支持 PING —— 大多数 PDO_MySQL 和 MySQLi 没问题,但自定义封装或老驱动可能静默失败,此时需手动验证 $pdo->getAttribute(PDO::ATTR_CONNECTION_STATUS) 或写个最小脚本调 $pdo->ping()。


















