hyperf rpc调用超时主因是服务节点不可达,需检查nodes配置是否为容器可解析地址、consul健康检查间隔与超时是否合理、防火墙是否放行跨容器流量,以及服务是否监听0.0.0.0而非127.0.0.1。

Hyperf RPC 调用超时,八成不是代码写错了,而是网络没通透或 Consul 心跳节奏没对上——尤其当你看到 Cannot select any node from load balancer 或 service not found 时,基本可以断定:服务节点压根没被负载均衡器“看见”,更谈不上发请求。
nodes 配置错一个字符,RPC 就永远连不上
Hyperf 的 JSON-RPC 客户端不会自动发现服务,它只认 config/autoload/rpc_client.php 里 nodes 数组写的地址。哪怕 Consul 里服务注册成功了,只要这里填的是 127.0.0.1 或 localhost,容器内调用必失败:
- 容器 A 里写
['host' => '127.0.0.1', 'port' => 9501]→ 实际连的是自己,不是服务提供者容器 - 应改用 Docker 自定义网络内可解析的名称,比如
hyperf-provider(前提是两容器在同一个 network 下) - 若用 Consul 做服务发现,
nodes必须为空数组[];一旦非空,Hyperf 就跳过 Consul,只从静态列表选节点 - 别信“我 ping 得通”,
ping走 ICMP,RPC 走 TCP,得用nc -zv hyperf-provider 9501验证端口级连通性
Consul 心跳间隔设太短,服务刚注册就被踢下线
Consul 不是等你“手动下线”,而是靠健康检查反复探测。如果心跳间隔(check.interval)或超时(check.timeout)配得比你的业务响应还激进,服务一注册就变 critical:
-
check.timeout设 1s,但你的/health接口因 DB 连接池卡住,平均耗时 1.3s → 每次探测都失败 -
check.http地址写http://127.0.0.1:9501/health→ Consul Server 在宿主机,根本访问不到容器内回环地址 - 正确写法是
http://hyperf-provider:9501/health(同网络)或宿主机可路由的真实 IP(如172.18.0.5) - Consul 默认每 10s 探测一次,但如果你在
consul.php里显式配了interval,务必确认该值 ≥ 后端接口 P95 响应时间 + 网络毛刺余量
RPC 超时日志里藏了真实病因
别只盯着 “timeout” 字样。Hyperf 的 RPC 超时分三层,报错不同,处理方式也完全不同:
-
ConnectException或Connection refused→ 连接建立失败:查nodes地址、防火墙、容器网络、服务是否监听0.0.0.0 -
RequestException且带read timed out→ 连接已建好,但服务端迟迟不返回:查业务逻辑阻塞、下游 Redis/MySQL 延迟、协程未 yield - 日志出现
wait timeout或Too many connections→ 连接池耗尽:不是网络问题,是并发请求数超过了pool.max_connections - 用
curl -v --connect-timeout 2 --max-time 8 http://hyperf-provider:9501/health可快速区分是 connect 卡住,还是 read 卡住
真正难排查的,是那些“看起来能通,但 Consul 就是不认为健康”的情况——往往因为健康检查路径返回了 200,但 body 是 {"status":"down"},而你又没在 Consul UI 里点开详细检查日志,只看状态图标就以为没问题。











