首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Dubbo 路由策略深度解析

Dubbo 路由策略深度解析

作者头像
阿特拉斯
发布2026-07-14 19:53:10
发布2026-07-14 19:53:10
180
举报
本文记录 Dubbo 当前路由链、主要路由策略行为,以及解释当前实现形态的历史提交。重点分析提供者过滤、灰度/金丝雀流量、服务发现迁移,以及路由与负载均衡的顺序关系。

调用链

路由发生在负载均衡之前。正常消费端路径:

消费者调用链
消费者调用链

1. AbstractClusterInvoker.invoke(Invocation) 向目录请求可用调用器

2. DynamicDirectoryServiceDiscoveryRegistryDirectory 返回当前调用器列表

3. RouterChain 为当前地址快照选择 SingleRouterChain

4. SingleRouterChain.simpleRoute(...) 先应用状态路由器

5. 若存在非状态/普通路由器,在状态路由器后应用

6. 具体集群调用器收到路由后的列表

7. 具体集群调用器调用 select(...)

8. LoadBalance 从路由候选集中选择一个提供者

重要顺序:

服务发现 / 注册中心通知

-> 目录调用器刷新

-> 路由链过滤

-> 集群容错

-> 负载均衡选择

-> 提供者调用

RouterChain.buildSingleChain(...) 加载遗留 RouterFactory 扩展和 StateRouterFactory 扩展。普通路由器按 Router::compareTo 排序,状态路由器链接成以 TailStateRouter 结尾的链。

SingleRouterChain.simpleRoute(...) 先通过 headStateRouter 路由,之后才将 BitList 结果转为普通列表并运行普通路由器。因此负载均衡器永不见完整注册中心地址列表,除非路由让其不变。

已注册状态路由器

状态路由器注册于:

dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory

当前注册:

代码语言:javascript
复制
MockStateRouterFactory

本文聚焦条件路由、标签路由、脚本路由、应用级服务发现路由和灰度/金丝雀路由模式。

已注册状态路由器
已注册状态路由器

路由链并发模型

RouterChain 双链并发模型
RouterChain 双链并发模型

RouterChain 现维护两个 SingleRouterChain 实例:mainChainbackupChain。地址通知期间将流量切换到备份链,刷新主链,切换目录地址引用,再将流量切回主链并刷新备份链。

此设计存在因为路由状态绑定到特定调用器列表。请求不能用新 BitList 穿旧链路由,或用旧 BitList 穿新链路由。

历史注记:

• 提交 3531a7d681[3.0] Feature/state router (#6844))引入状态路由器、BitList 和状态路由器工厂注册。原设计包含路由计算地址列表缓存

• 提交 77e6708ebd[3.0] Refactor state router iterator to router chain (#9424))将状态路由器重构为后续使用的链模型

• 提交 4cc3b28a3e[3.0] Add Router Snapshot Print Support (#9517))添加路由快照,使空路由诊断可见

• 提交 5ef3b4fb2eAdd dual chain support for state router, prevent update when invoke (#10691))将 RouterChain 拆为双 SingleRouterChain 实例,避免调用路由时更新链

• 提交 b56687957eFix invokers has changed when router chain switch (#11248))修复调用器快照与路由链切换时可能不匹配的竞争。当前代码保持临时 notifyingInvokers 引用以决定用刷新主链还是当前备份链

操作含义:

• 路由非对任意列表应用的无状态过滤器。链与 BitList 源列表耦合

• 地址通知、规则刷新和请求路由对并发敏感

• 路由快照是"路由后无提供者"情况的一级诊断路径

条件路由

ConditionStateRouter 实现经典规则形状:

when 条件 => then 条件

左侧匹配消费者 URL 和调用。右侧过滤提供者 URL。示例:

method=sayHello => region=hangzhou

attachments[user_id]=1~100 => region=hangzhou

arguments[0]=vip => env=gray

重要行为:

• 空 or truewhen 表示规则对所有匹配请求适用

• 空 or falsethen 表示显式空结果,对匹配消费者实际是黑名单规则

• 若 when 不匹配,返回原始调用器列表

• 若 then 匹配提供者,返回匹配子集

• 若 then 匹配无提供者且 force=true,返回空列表

• 若 then 匹配无提供者且 force=false,路由器回退到原始输入列表

• 匹配委托给 ConditionMatcherFactory 实现

动态条件规则由 ListenableStateRouter 子类处理:

ServiceStateRouter 监听 service-key.condition-router

AppStateRouter 监听 application.condition-router

ProviderAppStateRouter 在看到提供者地址后订阅提供者应用的 .condition-router 规则

历史注记:

• 早期条件路由用硬编码 MatchPair 模型处理 URL 参数和参数

• 提交 8c786cdf01Add 'label match' support for override and tag rules (#11094))将条件匹配移到匹配器 SPI 抽象。添加参数匹配、附件匹配、URL 参数匹配、范围匹配、通配符匹配和 ProviderAppStateRouter

• 提交 31e1aa6b59Add volatile modifier to some variables in ListenableRouter (#8579))是小但重要的并发标记:规则可从配置中心通知异步更新

• 提交 a93624e8cfNew condition router v3.1 (#14456))添加 MultiDestConditionRouter,支持单条件规则下多加权目标

风险轮廓:

force=true 可故意路由到空提供者集。对黑名单和流量切断有用,但规则格式错误时危险

force=false 通过回退原始列表保护可用性,但无提供者匹配时可静默忽略预期隔离

• 匹配器可扩展性强大,但每个匹配器参与热路径路由

多目标条件路由

v3.1 条件路由将单 then 目标泛化为多加权目标:

configVersion: v3.1

scope: service

force: false

runtime: true

enabled: true

conditions:

- from:

match: env=gray

to:

- match: env=gray

weight: 900

- match: env=normal

weight: 100

MultiDestConditionRouter 评估 from.match 条件。对每个 to 分支构建提供者子集。非空子集以权重加入 DestinationSet,然后随机选一个目标子集。

这是与灰度/金丝雀流量最直接对齐的条件路由形式。仍返回提供者子集而非最终提供者。路由器选目标子集后,负载均衡仍在该子集内选具体提供者。

风险轮廓:

• 加权目标选择发生在负载均衡前

• 权重控制目标子集概率,非每提供者概率

• 若一目标子集有多个提供者,另一子集少,最终每提供者流量分布受目标权重和下游负载均衡共同影响

标签路由

TagStateRouter 分离带标签和不带标签流量。请求标签先来自调用附件 dubbo.tag,再来自消费者 URL 参数。提供者标签可为静态 URL 参数或配置中心动态标签规则。

重要行为:

dubbo.tag=* 跳过标签路由,返回所有当前调用器

• 若无动态标签规则,用静态提供者 URL 标签

• 带标签请求先试动态标签地址

• 若无动态标签地址,检查静态提供者标签

• 若无匹配带标签提供者且 force.tag 非 true,回退不带标签提供者

• 若 force.tag=true,空带标签结果保持空

• 不带标签请求排除动态标签分组中的提供者,再排除静态标签提供者

• 动态标签规则按提供者应用订阅

多级选择器通过渐进修剪后缀支持标签回退:

beta|team1|partner1

-> beta|team1|partner1

-> beta|team1

-> beta

强制模式启用时,此回退禁用,只选精确标签。

历史注记:

• 提交 8c786cdf01Add 'label match' support for override and tag rules (#11094))添加 v3 标签规则按提供者 URL 参数匹配,非仅显式地址列表。并警告 v3 标签规则偏好 match 而非 addresses

• 提交 679ce4496ctag support multi level (#12673))用 | 作分隔符添加分层标签回退

• 提交 c63d247ed7fix(cluster): support broadcast and wildcard tag routing (#15876))添加通配符标签路由。关键行为是 dubbo.tag=* 返回所有提供者而非应用标签隔离

风险轮廓:

• 标签路由有可用性回退到不带标签提供者,除非 force.tag=true

• 此回退对金丝雀安全方便,但可违反严格隔离预期

• 通配符标签路由刻意绕过标签过滤;对广播或管理调用有用,但不应与正常带标签请求混淆

脚本路由

ScriptStateRouter 评估 JSR-223 脚本并期望脚本返回列表或数组调用器。向脚本传这些绑定:

invokers

invocation

context

重要行为:

• 脚本引擎类型从 type URL 参数读,默认 Dubbo 默认脚本类型

• 脚本引擎按类型缓存

• 规则在构造器中编译一次

• 若编译失败,路由器记录日志并回退原始调用器列表

• 若执行失败,记录日志并返回原始调用器列表

• 返回调用器与原始 BitList 取交集,脚本不能添加当前候选集外的提供者

• 执行在受限 AccessControlContext 中运行,只授予 RuntimePermission("accessDeclaredMembers")

动态应用级脚本路由由 AppScriptStateRouter 处理,监听提供者应用的 .script-router 规则并从 YAML 配置重建 ScriptStateRouter

历史注记:

• 脚本路由早于当前状态路由器模型,但现作为状态路由器参与

• 提交 e07e5e294bFix get method name from invocation (#12519))改变方法名日志使用 RpcUtils.getMethodName(invocation)

• 提交 d2eb0ef458Optimize ConcurrentHashMap#computeIfAbsent have performance problem in jdk1.8 (#11326))将直接 ConcurrentHashMap.computeIfAbsent 替换为 Dubbo 工具助手处理引擎缓存查找,因脚本路由在热路径

风险轮廓:

• 脚本路由最灵活但最难推理

• 依赖运行时脚本引擎存在

• 格式错误脚本失败开放,返回原始调用器列表

• 脚本执行受限但仍比声明式条件或标签规则实质上风险更高

应用级服务发现路由

应用级服务发现不只一个路由类。它在路由开始前改变地址源。

ServiceDiscoveryRegistryDirectory 收服务实例通知,转实例 URL 和元数据为协议服务键,创建或复用调用器,构建 BitList,刷新集群层其余部分使用的同一 RouterChain

重要行为:

buildRouterChain(...) 构建路由链前添加 registry-type=service

• 实例地址在调用器创建前去重

• 不支持协议跳过

• 元数据用于匹配服务接口、分组、版本、协议和端口

• 若消费者协议未指定,存在时先选偏好协议;否则用主非额外协议

• 应用级和服务级配置器可在调用器创建前覆盖目录和提供者 URL

• 多分组引用可将每分组调用器包装在 StaticDirectory,它本身有路由链

历史注记:

• 提交 ff39bf36c3Add 3.0 Multi Instance Support (#8662))是主要服务发现迁移基线

• 提交 1dfb114734[3.0] Multi Instances Related Refactor (#8737))和后续服务发现提交精化多实例行为

• 提交 7c7788d8b7Add preferred protocol support for application service discovery (#14849))在回退默认主协议前添加偏好协议选择

• 提交 a35af2742aRemove duplicated invokers in registry notification (#15060))在调用器创建前添加注册通知 URL 去重

• 提交 2170f0fa90fix thread safety issue of ConsumerConfigurationListener (#15707))将目录监听器 ArrayList 替换为 CopyOnWriteArrayList

风险轮廓:

• 应用级发现改变候选宇宙,在路由规则运行前

• 服务元数据正确性直接影响哪些协议服务键可引用

• 重复通知数据、偏好协议选择和配置器覆盖都影响最终路由提供者集

迁移与金丝雀发布

MigrationInvoker 管理接口级发现与应用级服务发现间迁移。支持三步:

FORCE_INTERFACE

APPLICATION_FIRST

FORCE_APPLICATION

APPLICATION_FIRST 中,Dubbo 可按推广百分比和可用性偏好服务发现调用器同时回退接口级调用器:

promotion < 100 触发按比例随机回退接口模式

decideInvoker() 只在当前可用时偏好服务发现

• 地址比较器在强制迁移前检查迁移是否满足配置阈值

• 规则支持全局默认、接口特定覆盖和应用映射特定覆盖

历史注记:

• 提交 0ae2ccc99coptimization MigrationInvoker promotion (#9270) (#9271))修复推广检查,使 promotion=100 不必要运行随机比较路径

• 提交 c4847d5934[3.0] Add dynamic decide invoker in APPLICATION_FIRST mode (#9967))使 APPLICATION_FIRST 每次调用重检查服务发现调用器可用性,而非坚持过期偏好调用器

• 提交 819375bf44[3.0] Always get mapping from remote when migrate (#9988))表示迁移正确性依赖最新远程服务名映射

• 提交 fc0f88f4f2Fix MigrationRule changing when load consumer default value (#13237))阻止默认值查找改变规则对象

此迁移机制是发现模式本身的金丝雀路径。与标签金丝雀或条件规则金丝雀不同,但有类似发布控制:百分比、阈值、延迟和强制。

灰度与金丝雀模式

Dubbo 无需名为 GrayRouterCanaryRouter 的单类实现灰度发布。当前代码库通过多种可组合机制支持灰度/金丝雀行为:

灰度/金丝雀路由模式
灰度/金丝雀路由模式

模式

机制

注记

头/附件基金丝雀

条件路由 attachments[...] => provider-label

声明式易诊断

参数基金丝雀

条件路由 arguments[n] => provider-label

对租户或用户 ID 路由有用

提供者标签金丝雀

标签 v3 match 规则

从提供者参数构建标签分组

分层金丝雀

标签选择器 beta|team|partner

非强制时回退更广标签

加权金丝雀

多目标条件路由

负载均衡前按权重选目标子集

Mesh 风格金丝雀

标准 Mesh 规则路由器

用虚拟服务 + 目标规则子集

发现模式金丝雀

MigrationInvoker APPLICATION_FIRST + promotion

从接口发现向应用发现滚动流量

关键区别是机制先过滤还是先选择加权目标:

• 条件/标签路由通常过滤到一子集

• 多目标和 Mesh 路由先按权重选目标子集,再返回该子集

• 路由子集产生后负载均衡仍发生

路由与负载均衡

路由 vs 负载均衡
路由 vs 负载均衡

路由回答:

哪些提供者对该调用可用?

负载均衡回答:

哪一个提供者应处理本次尝试?

此区别对解释重要:

• 若路由返回 10 提供者,负载均衡从这 10 中选择

• 若路由返回 1 提供者,负载均衡实际绕过

• 若强制路由返回 0 提供者,集群层收到无提供者

• 若非强制路由无法匹配任何提供者,可返回原始列表,负载均衡继续如同规则未窄化流量

failover 中,每次重试重新列表和重新路由再选择

未来变更验证考量

未来路由变更应包含测试:

• 请求并发路由时 RouterChain 地址更新

• 目录与路由链间 BitList 源列表一致性

• 空路由结果的路由快照输出

• 条件路由 force=trueforce=false 空结果行为

• 附件、参数、URL 参数、通配符和范围匹配器

• 多目标加权选择和子集大小与负载均衡交互

• 标签路由动态规则、静态标签、不带标签回退、force.tagdubbo.tag=*

• 分层标签回退带和不带强制模式

• 脚本编译失败和执行失败回退

• 并发路由创建下脚本引擎缓存行为

• 带重复通知和偏好协议元数据的应用级服务发现

• 迁移 APPLICATION_FIRST 可用性回退和推广百分比

• 配置中心删除事件、格式错误规则和规则监听器清理

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-07-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 超级AI技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 调用链
  • 已注册状态路由器
  • 路由链并发模型
  • 条件路由
  • 多目标条件路由
  • 标签路由
  • 脚本路由
  • 应用级服务发现路由
  • 迁移与金丝雀发布
  • 灰度与金丝雀模式
  • 路由与负载均衡
  • 未来变更验证考量
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档