Hyperf RPC 默认短连接导致高延迟,必须通过配置 keep_alive 和连接池实现长连接复用;JSON-RPC 需客户端加 'keep_alive' => true 且服务端启用 open_keepalive,TCP 多路复用则依赖 client_count 配置,连接池需单独配置 pool 键且按节点隔离。

Hyperf RPC 默认走短连接时,每次调用都要经历 TCP 三次握手 + TLS 握手(如果启用 HTTPS),响应延迟直接多出 1–3 个 RTT。这不是代码慢,是网络层在拖后腿。必须强制复用连接,否则压测一上万 QPS 就卡在 connect() 系统调用上。
为什么默认 RPC 客户端不复用连接
Hyperf 的 hyperf/rpc-client 在未显式配置连接池或协议复用时,底层会退化为每次 new 一个 Swoole\Coroutine\Http\Client 或裸 TCP Client —— 这类实例生命周期仅限单次请求,用完即销毁。哪怕你用了协程,也拦不住连接本身的重建开销。
- HTTP/JSON-RPC 协议下,没设
keep_alive或没配连接池,就等同于 HTTP/1.0 - TCP 直连模式(如
Hyperf\RpcMultiplex)若client_count设为 1 且没启多路复用,仍是“伪长连”:单连接串行,无法并发 - gRPC over HTTP/2 虽天然支持多路复用,但 PHP 的
grpc/grpc扩展默认不开启协程支持,容易阻塞 Worker
开启 TCP 长连接的两个关键配置点
不是加个 keep_alive => true 就完事。Hyperf 的长连接生效依赖服务端和客户端双向配合,且不同协议路径不同。
- 对 JSON-RPC:在
config/autoload/services.php的 consumer 配置里加'options' => ['keep_alive' => true],同时服务端server.php必须启用open_keepalive => true(仅对 HTTP 类型 server 有效) - 对 TCP 多路复用(
rpc-multiplex):长连接由协议层保障,无需额外 keep-alive;重点是设对client_count(建议 4–8),它代表预建的并发连接数,不是单连接上的 channel 数 - 务必禁用
http_client的timeout中的connect_timeout过长(如 >3s),否则连接池等待新连接时会卡住整个协程
连接池复用必须绕开的三个坑
很多人以为配了 max_connections 就自动池化,结果压测发现连接数还是飙升 —— 实际上,Hyperf 的 RPC 连接池只对「同一服务节点」生效,且受协议类型强约束。
- Redis/MySQL 连接池配置(
redis.php、databases.php)对 RPC 调用完全无效:RPC 客户端用的是独立的ConnectionPool实现,需单独配pool键 - 多节点服务(如注册中心返回多个 IP)下,每个 IP 地址都会维护独立连接池;若节点数动态变化,旧池不会自动清理,可能残留大量 idle 连接
-
pool.min_connections设太高(如 >10)会导致启动时预热连接过多,冷启动慢;设太低(如 0)则首请求必然触发新建连接,延迟毛刺明显
验证是否真正复用了连接
别只看文档或日志。最直接的方式是抓包或查系统连接状态:
- 用
ss -tan | grep :9502 | wc -l查服务端 ESTABLISHED 连接数,高并发下稳定在个位数(如 4–8),说明client_count生效;若随 QPS 线性增长,就是没复用 - 在客户端协程内打点:
var_dump(Swoole\Coroutine::getPcid())和Co::gethostbyname()结合,确认多次调用是否命中同一个 socket fd - 开启
hyperf/metrics并暴露hyperf_rpc_client_pool_used_connections指标,观察 used/idle 曲线是否平滑波动而非持续爬升
真正的连接复用,是让「连接生命周期」脱离「请求生命周期」。这点一旦没对齐,再多的协程优化都白搭 —— 因为你的应用还在用脚本思维写常驻服务。


















