理解路由和负载均衡的协作机制,是构建高可用、可管控的分布式系统的关键。下面这张图清晰地展示了在一次服务调用中,两者如何像筛子一样层层过滤,最终选定目标。
flowchart TD
A[服务消费者发起调用] --> B["Directory<br>获取所有服务提供者<br>(Invoker列表)"]
B --> C["路由链<br>(Router Chain)"]
C --> D[条件路由]
C --> E[标签路由]
C --> F[脚本路由]
subgraph G [路由阶段:初步筛选]
D --> H["按预设规则(如IP、标签)<br>过滤提供者"]
E --> H
F --> H
end
H --> I["筛选后的<br>有效提供者子集"]
I --> J["负载均衡<br>(LoadBalance)"]
J --> K[随机算法]
J --> L[轮询算法]
J --> M[最少活跃调用]
J --> N[一致性哈希]
subgraph O [负载均衡阶段:最终选择]
K --> P["基于特定算法<br>选定唯一目标"]
L --> P
M --> P
N --> P
end
P --> Q[向最终选定的提供者发起调用]
下面我们详细解读图中的两个核心阶段,并介绍常见的策略。
📍 路由:流量的导航仪
路由的核心作用是根据预设的业务规则,对服务提供者进行初步筛选,相当于为流量设置"导航路线"。
| 路由类型 | 工作方式 | 典型应用场景 |
|---|---|---|
| 条件路由 | 通过类自然语言的规则(如 host = 192.168.1.1 => host = 192.168.0.*)来匹配和过滤提供者。 |
蓝绿发布 、机房就近路由、读写分离。 |
| 标签路由 | 为提供者打上标签(如 env=gray),消费者通过 RpcContext携带标签,将流量路由到匹配的提供者集群。 |
灰度发布、多环境隔离(如测试环境与生产环境隔离)。 |
| 脚本路由 | 支持使用 JavaScript 等脚本语言编写高度自定义的路由逻辑,灵活性极高。 | 需要根据复杂业务参数进行路由的特定场景。 |
⚖️ 负载均衡:流量的调度员
当路由规则圈定出一个"合格提供者池"后,负载均衡算法登场,负责从这个池中基于特定算法选择一个最优的提供者进行本次调用。
| 负载均衡策略 | 算法核心 | 适用场景 |
|---|---|---|
| 随机 | 按权重随机选择。调用量越大分布越均匀。 | 节点性能相近,请求耗时均匀的场景。 |
| 轮询 | 按权重设置轮询比率,依次请求。 | 需要严格均匀分配流量的场景,但对慢节点不友好。 |
| 最少活跃调用 | 优先选择当前正在处理的请求数(活跃数)最少的节点。 | 节点性能差异较大,或请求耗时波动明显的场景,能自动规避高负载节点。 |
| 一致性哈希 | 相同参数的请求总是发到同一提供者,适用于需要保持会话状态的场景。 | 分布式缓存、有状态服务,能减少节点变动带来的影响。 |
💡 如何选择与配置?
-
策略选择依据:
-
如果需要进行流量隔离 (如灰度、分环境),重点配置路由规则。
-
如果追求调用性能 和资源利用最优化 ,重点调整负载均衡策略。
-
对于幂等性 操作(如查询),可使用支持重试的
Failover容错模式;对于非幂等 操作(如支付),应使用Failfast快速失败模式。
-
-
配置方式:路由规则和负载均衡策略都可以在引用服务时进行配置,并且支持动态调整,无需重启应用。
<!-- 示例:在服务引用端配置负载均衡和集群容错模式 --> <dubbo:reference id="demoService" interface="com.example.DemoService" loadbalance="leastactive" cluster="failover" />
💎 总结
总而言之,路由和负载均衡在服务调用链中是协同工作的两层过滤器:**路由是"导航",负责制定宏观的流量导向规则;负载均衡是"选择器",负责在规则圈定的范围内进行微观的、最优的节点选择。** 理解它们的区别与联系,能帮助你更好地设计和管控你的微服务架构。
希望这份解读能帮助你彻底理解路由与负载均衡的协作机制。如果你对特定场景下的配置或某种策略的源码实现有更进一步的兴趣,我们可以继续深入探讨。