hyperf应用在k8s中频繁重启或503,主因是probe配置不合理:livenessprobe误用/heath(查依赖)导致雪崩,应改用轻量/ping;readinessprobe须用/ready检查关键依赖并设initialdelayseconds=15–25s,避免启动未完成即接入流量。

Hyperf 应用在 K8s 中频繁重启或流量 503,大概率不是代码问题,而是 readinessProbe 和 livenessProbe 配置不合理 —— 尤其是没区分「启动慢」和「运行中假死」,或健康端点返回逻辑与探针语义冲突。
为什么 Hyperf 的 /health 默认不能直接用于 livenessProbe
Hyperf 默认提供的 /health 是一个综合健康检查接口,通常会检查数据库连接、Redis、配置加载等依赖项。这在 livenessProbe 场景下非常危险:
- 如果 DB 临时抖动,
livenessProbe失败 → K8s 重启容器 → 所有连接池重建 → 加剧 DB 压力,形成雪崩循环 -
livenessProbe的目标是检测「进程是否僵死」,不是「依赖是否可用」;它应该只验证应用自身是否能响应请求、线程是否卡死 - Hyperf 的 Swoole 主进程若未崩溃,但 Worker 进程全部阻塞(如协程死锁),
/health可能仍返回 200(因响应由 Manager 进程代发)
✅ 正确做法:为 livenessProbe 单独暴露轻量端点(如 /ping),仅做 HTTP 状态码返回,不查任何外部依赖。
readinessProbe 必须检查依赖,且要容忍启动延迟
Hyperf 启动时需加载配置、连接 Redis/DB、注册服务发现等,这些耗时可能达 10–30 秒(尤其 Java 项目常被拿来类比,但 PHP+Swoole 实际更短,仍不可忽略)。若 readinessProbe 过早触发,会把未初始化完成的 Pod 提前加入 Service Endpoints,导致 500 或超时。
- ✅ 使用
/ready端点,且内部必须包含关键依赖检查(如PDO::query("SELECT 1")、$redis->ping()) - ✅ 设置足够大的
initialDelaySeconds(建议 15–25s,根据实际 warmup 日志定) - ❌ 不要用
tcpSocket检 9501 端口 —— Swoole 监听端口成功 ≠ 应用 ready,Worker 可能还在初始化 - ⚠️ 注意:Hyperf 的
HealthCheck组件默认不开启/ready,需手动注册路由并控制检查粒度
避免 startupProbe 缺失导致的「启动即重启」
Hyperf 在 Swoole reload 或冷启动时,主进程 fork Worker 有短暂窗口期(livenessProbe 已开始探测,可能因 Worker 未就绪而失败。K8s 1.16+ 支持 startupProbe,专治此问题:
- ✅ 配置
startupProbe代替过长的initialDelaySeconds,例如:
startupProbe:
httpGet:
path: /ping
port: 9501
failureThreshold: 30
periodSeconds: 2
timeoutSeconds: 1
- 含义:最多等待 60 秒(30 × 2),期间只要有一次
/ping成功,就认为启动完成,随后才启用livenessProbe和readinessProbe - ✅ 这比把
livenessProbe.initialDelaySeconds设为 60 更安全 —— 启动失败时能更快暴露问题,而不是卡在“等待”状态
exec 探针在 Hyperf 中基本不适用
Hyperf 是常驻内存的 Swoole 应用,没有传统「进程退出即故障」的语义。用 exec 执行 ps aux | grep hyperf 或 kill -0 $PID 完全无效:
- Swoole 主进程始终存活,但业务可能已卡死(如所有协程 hang 在
co::sleep()) -
exec在容器内执行命令开销大,且无法感知协程调度状态 - K8s 的
exec探针超时后会 kill 掉该次 exec 进程,但对 Swoole Worker 无影响,纯属干扰
✅ 唯一可接受的 exec 场景:仅用于容器启动脚本中生成标记文件(如 touch /tmp/started),再配 exec: ["test", "-f", "/tmp/started"] 做 startup 探测 —— 但这已被 httpGet + startupProbe 更优雅替代。
最易被忽略的一点:Hyperf 的健康端点必须用 GET 方法,且不能带中间件(如鉴权、日志记录),否则探针请求可能被拦截或拖慢;同时确保该路由不走服务发现或负载均衡逻辑(如不要通过 HttpClient 调自己),否则形成自循环依赖。











