Dubbo 服务发现与路由的概念有什么不同?

#中间件#面试八股

Dubbo 服务发现与路由的概念有什么不同?

结论先行:服务发现回答“有哪些实例可用”,路由回答“这次调用允许去哪些实例”。发现面向注册中心,产出全量地址列表;路由面向调用规则,在列表上做减法。两者之后才是负载均衡,回答“具体选哪一台”。

一、一条链路上的三次筛选

Registry 推送全量地址
        │
        ▼
Directory(目录)──── 保存 invoker 列表,注册中心变更时刷新
        │
        ▼
Router(路由)────── 条件路由 / 标签路由 / 脚本路由,过滤出候选集
        │
        ▼
LoadBalance(负载均衡)── 从候选集里挑一个
        │
        ▼
Invoker(真正发起调用)

三者串行执行,顺序不能颠倒:路由必须看到全量列表才能做灰度比例切分,负载均衡必须看到过滤后的列表才不会把流量打到被排除的机器上。

二、概念对比

维度服务发现服务路由
数据来源注册中心推送规则配置(控制台、配置中心、代码)
作用对象全部实例候选实例子集
变更频率随实例上下线变化随发布、灰度、容灾演练变化
失效后果拿不到地址,调用直接失败流量打错机器,可能跨机房或打到灰度
典型实现RegistryDirectory + NotifyListenerConditionRouter、TagRouter、ScriptRouter

三、路由的三种常见形态

类型规则表达典型用途
条件路由消费者条件 => 提供者条件,支持 host、method、region 等键读写分离、黑白名单、同机房优先
标签路由请求打标 tag=gray,只匹配同标签实例金丝雀发布、全链路灰度
脚本路由用脚本语言写匹配逻辑复杂业务规则、临时活动流量隔离

条件路由示例(YAML 形式,等价的规则串以 => 分隔消费方与提供方条件):

# 只允许上海机房的消费者调用上海机房的提供者
force: false
enabled: true
runtime: true
conditions:
  - "region=shanghai => region=shanghai"

force 决定“过滤后为空”时的行为:false 表示降级为不过滤(宁可跨机房也别失败),true 表示严格失败。生产上灰度场景常用 force=true,容灾场景常用 force=false。

标签路由在代码里的写法:

RpcContext.getClientAttachment().setAttachment("tag", "gray");
userService.getById(1L);

提供者需要在启动参数里声明自己属于哪个标签:-Ddubbo.provider.tag=gray。

四、规则生效的两个时机

时机行为风险
启动时从注册中心拉取全量规则,缓存在本地注册中心不可用则回退到本地缓存文件
运行期订阅 routers/configurators,变更即通知规则写错会立刻影响全部消费端

所以灰度规则上线前要在测试环境验证,并保留一键回滚;force=false 是最后一道保险。

常见追问

  • 追问:路由和负载均衡能合并吗?不能。路由是“能不能去”,属于可用性约束;负载均衡是“去哪个更好”,属于性能优化,语义完全不同。
  • 追问:路由规则存在哪里?Dubbo 把规则写到注册中心的 routers 或 configurators 目录,消费端订阅后本地生效,所以规则变更不需要重启应用。
  • 追问:为什么路由要在消费端做?在消费端做可以感知全量实例、按调用维度灵活切换,且不增加提供者负担;代价是每个消费端都要同步规则。

小结

  • 发现是“拉名单”,路由是“按规则筛名单”,负载均衡是“从名单里挑一个”。
  • 条件路由管机房与黑白名单,标签路由管灰度,脚本路由管临时复杂规则。
  • 记住 force 参数:它决定筛选结果为空时是报错还是降级。
  • 路由规则通过注册中心下发,运行期可改,不必重启。
笔记加载中…