hyperf的heartbeat不是开关而是需协同配置的数值型探测间隔,必须设为正整数(如135)、≤max_idle_time(如270.0)、严格小于mysql wait_timeout(如300),并配合wait_timeout(5.0)、attr_timeout(3)及min_connections(≥5)共同生效。

Hyperf MySQL 心跳检测不是开关,而是协同参数
直接在配置里写 heartbeat => true 或 heartbeat => 1 不起作用——Hyperf 的 heartbeat 是个数值型探测间隔(单位秒),设为 -1 才禁用,设为正整数才启用,且仅对空闲连接生效。它本身不“主动保活”,而是配合后台空闲检查线程 IdleConnectionChecker 工作。
-
heartbeat值必须 ≤max_idle_time,否则根本没机会触发检测 - 若
max_idle_time≥ MySQL 的wait_timeout(比如 MySQL 是 300 秒,你设了 360),连接会在池里“睡过头”,取出时必然失效 - 查 MySQL 实际
wait_timeout:执行SHOW VARIABLES LIKE 'wait_timeout';,别依赖默认值(28800 秒) - 推荐组合(以 MySQL
wait_timeout = 300为例):max_idle_time => 270,heartbeat => 135
配置位置和必须同时调整的三个参数
心跳检测必须写在 config/autoload/db.php 对应数据库配置的 pool 下,不是全局配置。光改 heartbeat 没用,以下三项必须同步调:
-
max_idle_time:设为wait_timeout - 30(留缓冲),单位秒,类型是float,别写成整数270而应写270.0 -
wait_timeout(连接池级):这是协程等待空闲连接的超时,建议设5.0,不是调小它来“解决断连”,设太小(如0.1)会导致排队失败泛滥 -
options.ATTR_TIMEOUT:PDO 执行超时,建议3,防慢查询拖垮连接;漏配它,2006 错误常由单条慢 SQL 触发后连接被 MySQL 主动关掉
验证心跳是否真在运行
不能只看日志有没有 “heartbeat” 字样——Hyperf 默认不打心跳日志。真正有效的验证方式是:
- 用
hyperf:pool-status命令观察idle数值变化:若idle连续几分钟不变,说明heartbeat或max_idle_time配错,空闲连接没被回收或探测 - 手动模拟“僵尸连接”:临时把 MySQL 的
wait_timeout改成10,等 15 秒后再发起查询,如果仍报2006 MySQL server has gone away,说明心跳未生效 -
DB::connection()->getPdo()->ping()在命令行跑一下,确认驱动支持 PING;不支持时才考虑配checker => 'SELECT 1',但该语句不能在事务中执行
容易被忽略的 min_connections 和驱动依赖
很多人配完心跳还是出问题,根源常在这两个地方:
-
min_connections别设0或1:冷启动或低频后突增流量时,唯一连接若已失效,整个池就卡死。生产建议 ≥5,容器部署可设10 - 驱动必须支持协程:确认
php --ri swoole输出含support coroutines: enabled,且扩展加载的是 Swoole 5.0+;用原生mysqli或未 Hook 的 PDO 会绕过协程机制,心跳无效 - 容器内注意网络:MySQL 地址别写
127.0.0.1,应填服务名(如mysql),否则心跳探测发不出去
实际生效靠的是 max_idle_time 和 heartbeat 的数值关系,而不是“开了没开”。配错时,要么连接池沉默地塞给你一个已关闭的连接,要么疯狂发 PING 把 MySQL 打挂——两者都难排查。











