hyperf长连接需显式配置swoole心跳参数与应用层心跳协同,仅设heartbeat_idle_time无效,必须配对heartbeat_check_interval;request_timeout不控制长连接生命周期;云环境下tcp keepalive不足,须加业务心跳帧;协程客户端超时需单独设置。

Hyperf 默认基于 Swoole 运行,但它的长连接超时行为不是开箱即用的“自动保活”,而是依赖你显式配置 Swoole 层的心跳参数 + 应用层语义心跳协同。不配或配错,连接会在 60 秒(默认值)后静默断开,尤其在云环境或反向代理后更明显。
heartbeat_idle_time 和 heartbeat_check_interval 必须配对生效
这两个参数只对启用 open_http2 或 WebSocket 模式下的长连接起作用,HTTP/1.1 短连接无视它们。单独设 heartbeat_idle_time 没用 —— Swoole 内部靠 heartbeat_check_interval 定期扫描空闲连接,再按 heartbeat_idle_time 判定是否踢出。
-
heartbeat_idle_time建议设为 60~180 秒:太短易误杀活跃会话(比如 LLM token 流间隔略长),太长则无法及时回收僵尸连接 -
heartbeat_check_interval应 ≤heartbeat_idle_time/ 2,常见组合是 60s / 15s 或 120s / 30s - Hyperf 启动前必须在
config/autoload/server.php的settings中写死,启动后改无效
request_timeout 不等于连接空闲超时,别混用
很多开发者把 request_timeout 当成“整个连接存活时间”,结果发现 WebSocket 连接 10 秒就断了 —— 其实 request_timeout 只控制单次 HTTP 请求(含 upgrade 到 ws 前的握手阶段)总耗时,和升级后的长连接生命周期无关。
- WebSocket 场景下,
request_timeout仅影响GET /ws握手请求本身,设太小会导致 upgrade 失败 - 真正管长连接存活的是
heartbeat_idle_time,不是request_timeout - Hyperf 默认
request_timeout是 60 秒,若你有大文件上传或慢查询前置逻辑,需单独调高,但不影响后续 ws 连接
云环境必须加应用层心跳,TCP KeepAlive 不够用
腾讯云 CLB、阿里云 SLB、Nginx 等中间件普遍设置 60~300 秒空闲回收,仅靠 TCP 层 net.ipv4.tcp_keepalive_* 参数无法穿透。Swoole 的 heartbeat_* 也只发空包,某些网关会丢弃纯 ACK 或无 payload 的帧。
- 必须在 WebSocket
onMessage或 HTTP 长轮询中,每 25~45 秒发送一次带业务标识的心跳帧,例如:{"type":"ping","ts":1747650859} - 服务端收到后应立即回
{"type":"pong"},并更新该连接的最后活跃时间戳 - 配合 Hyperf 的
ConnectionPool或自定义连接管理器,定期清理超过 2× 心跳间隔未响应的连接
协程客户端超时要单独设,否则拖垮整个连接
Hyperf 里用 Co\Http\Client 调下游(比如调 LLM API)时,它的超时和 Server 层完全隔离。漏设 read_timeout,一个卡住的模型请求会让整个协程挂起,导致该连接后续所有消息无法处理,最终被 heartbeat_idle_time 强制断开。
- 必须在每次 new
Co\Http\Client后立刻set()三个超时:connect_timeout、read_timeout、write_timeout -
read_timeout是最关键的,它从 header 收完开始计时,token 流式响应必须留足缓冲时间(建议 ≥ 30s) - 不要复用
Co\Http\Client实例跨请求,每个协程应新建 —— 它不是线程安全的
最容易被忽略的是:Hyperf 的 server.php 配置只影响 Swoole 主进程,而协程内发起的下游请求、数据库连接、Redis 调用,各自有一套超时体系,必须逐层检查,不能只盯着一个 heartbeat_idle_time。











