hyperf 中服务发现与负载均衡是两个独立机制,不可混用;自定义服务发现需实现 governanceinterface,自定义负载均衡需注册 loadbalancerinterface 实现类,并在 azure 环境中还需配置 tcp keepalive 与 lb 超时策略。

Hyperf 不能通过“修改 LoadBalancer 算法”来实现自定义服务发现策略——这是两个不同层级的机制,混用会导致配置失效或节点无法选取。
服务发现(Service Discovery)和负载均衡(Load Balancer)不是一回事
服务发现解决的是「有哪些可用节点」的问题,由 hyperf/service-governance 负责,从 Consul/Nacos/etcd 拉取实时节点列表;负载均衡解决的是「从已有节点里选哪个」的问题,由 hyperf/load-balancer 实现。如果你改了 load_balancer 配置(比如写成 'load_balancer' => 'my_custom'),但没注册对应类,Hyperf 启动时会直接抛出 InvalidArgumentException: Unknown load balancer "my_custom"。
常见错误现象:
- 在
services.php里写了自定义算法名,但没声明类,服务启动失败 - 把节点列表硬编码进
nodes数组,却指望服务发现自动更新——此时nodes完全被忽略 - 以为重写
RoundRobin::select()就能干预服务发现逻辑,实际它只接收已过滤健康的节点
真正要扩展服务发现,得实现 GovernanceInterface
Hyperf 的服务发现入口是 Hyperf\ServiceGovernance\Contract\GovernanceInterface。你要做的不是改负载均衡器,而是提供一个能动态返回节点列表的治理客户端。
实操建议:
- 新建类
App\Governance\VpcAwareGovernance,实现GovernanceInterface接口 - 在
getNodes(string $service)方法中,先调用原生 Consul 客户端拉取节点,再按 VPC 子网标签(如region=us-east-1a)做过滤 - 在
config/autoload/services.php中注册它:'publishTo' => App\Governance\VpcAwareGovernance::class - 确保该类被容器扫描到(加
@Inject或在dependencies.php显式绑定)
如果真要自定义负载均衡算法,必须注册到容器
假设你确实需要一致性哈希且带权重,不能只靠手动 new 对象——Hyperf 的消费者组件只认容器里注册的命名实例。
正确做法:
- 定义类
App\LoadBalancer\WeightedConsistentHash,实现Hyperf\LoadBalancer\LoadBalancerInterface - 在
dependencies.php中绑定:Hyperf\LoadBalancer\LoadBalancerInterface::class => App\LoadBalancer\WeightedConsistentHash::class - 在服务配置中仍写标准键名:
'load_balancer' => 'weighted_consistent_hash'(注意:这个字符串必须和你容器里注册的别名一致) - 别忘了在构造函数里注入
Hyperf\Contract\ConfigInterface来读取hash_key、replicas等参数
Azure VPC 环境下最容易被忽略的网络层干扰
即使你的 Hyperf 服务发现和负载均衡都配置正确,在 Azure VPC 中仍可能因网络层行为导致连接中断——这不是代码问题,而是 Standard Load Balancer 默认 4 分钟闲置超时 + 无 TCP RST 导致的静默断连。
表现是:
- PHP 协程里
yield $client->send()突然抛出"Connection reset by peer" - 日志显示请求发出去了,但没收到响应,也没有异常捕获
- Consul 页面显示所有节点健康,但部分请求持续超时
解决方案必须双管齐下:
- 在 Azure LB 规则上启用
Idle timeout (minutes)并设为 30+,同时勾选Reset idle TCP connections - 在 Hyperf 客户端侧启用 TCP keepalive:
stream_context_create(['socket' => ['tcp_keepalive' => true, 'keep_idle' => 60, 'keep_interval' => 10]])
不处理这一层,再精细的负载均衡策略也会被网络设备悄悄截断。











