hyperf服务不能靠传统http心跳检测,因其仅验证端口监听与路由注册,无法感知协程卡死、连接池耗尽、数据库超时或timer停摆等真实运行态问题,易导致“假活”——健康接口返回200但业务请求全部失败。

Hyperf 服务为什么不能靠传统 HTTP 心跳检测?
因为 HTTP 层面的心跳(比如用 curl http://host:8080/health)只验证了 Server 进程是否在监听端口、路由是否注册,但完全无法反映协程调度器是否卡死、Redis 连接池是否耗尽、数据库连接是否全部超时、或某个长期运行的 Timer 是否已停止触发——这些才是 Hyperf 实际运行中最容易出问题的点。
典型现象:健康接口返回 200,但业务请求全部超时或无响应;docker ps 显示容器 Running,top 看 CPU 很低,实际服务已“假活”。
用 HealthCheck 组件做真实态检测
Hyperf 官方 health-check 组件不是摆设,但它默认只检查 redis 和 database 连接,且不校验连接可用性——比如 Redis 连接池能建立,但 ping 不通,它照样报 healthy。
- 必须重写
RedisHealthChecker,在check()方法里执行$this->redis->ping()而非仅判断连接对象存在 - 数据库检查要加
SELECT 1查询,不能只依赖PDO::getConnection()是否抛异常 - 如果用了
ETCD或Nacos注册中心,需额外实现EtcdHealthChecker并检查getkey 是否成功 - 所有检查项必须设置超时(如
500ms),避免一个慢依赖拖垮整个健康接口
onWorkerStart 里启动独立心跳协程
光靠 HTTP 健康接口被动探测不够。真实生产环境需要主动自检:每 3 秒检查一次关键资源水位,并在异常时记录日志、触发告警,甚至主动退出进程让 supervisor 或 K8s 重启。
示例逻辑放在 onWorkerStart 回调中:
use Hyperf\Contract\OnWorkerStartInterface;
use Swoole\Coroutine;
<p>class HealthMonitor implements OnWorkerStartInterface
{
public function onWorkerStart($server, $workerId): void
{
Coroutine::create(function () {
while (true) {
// 检查协程数是否接近上限(如 > 90%)
if (Coroutine::stats()['coroutine_num'] > 1000 * 0.9) {
\Log::warning('Coroutine usage too high');
}
// 检查 Redis 连接池空闲数
$pool = \Hyperf\Redis\RedisFactory::get('default');
if ($pool->getAvailableCount() === 0) {
\Log::error('Redis pool exhausted');
}
Coroutine::sleep(3);
}
});
}
}</p>
注意:不要在这里直接调 exit(),应发信号给主进程或写标记文件,由外部守护程序决策是否重启。
K8s 中 livenessProbe 怎么配才不误杀?
很多人把 livenessProbe 的 initialDelaySeconds 设成 5,结果服务刚启动时健康接口还没就绪,K8s 就反复 kill + restart,形成恶性循环。
-
initialDelaySeconds至少设为15,给 Hyperf 完成 DI 容器加载、连接池预热、定时器注册留足时间 -
failureThreshold建议设为3,避免单次网络抖动导致重启 -
timeoutSeconds必须 ≤readinessProbe.timeoutSeconds,否则 readiness 先失败,liveness 还没来得及响应就已介入 - 路径别用
/health,改用/health/live,和 readiness 的/health/ready分开,语义更清晰
真正难的是判断“该不该重启”——比如 Redis 临时不可用,是等它恢复,还是立刻杀掉进程?这得结合你的业务容忍度来定,没有通用答案。











