Skip to content
Charles Shao
Go back

Dubbo 深挖 · Cluster 容错、负载均衡与路由

views

前一篇保证了 Directory 里的地址大体正确。真正决定「这次调用打哪台、失败了怎么办」的,是 Dubbo 最有辨识度的一层——Cluster

本篇把 Cluster 四件套拆开:Directory 提供候选人,Router 按规则裁剪,LoadBalance 做选择,Cluster 策略决定失败后的行为。配错这一层,轻则流量不均,重则把一次抖动放大成雪崩。

本文是 Dubbo 深挖系列的第 3 篇。架构开篇 → ② 注册发现 → ③ Cluster(本篇) → ④ 协议 Triple → ⑤ 流量治理

一句话定位:Cluster 层 = 在可用 Invoker 集合上做「过滤 → 选择 → 容错」;负载均衡只是其中一环,重试策略才是故障放大器的开关。

TL;DR

Table of contents

Open Table of contents

1. Cluster 四件套

Dubbo Cluster 四件套流水线。Directory 输出 Invoker 列表 → Router 链按条件/标签过滤 → LoadBalance 选出一个 Invoker → Cluster 策略执行调用并在失败时 Failover/Failfast/…。底部强调:列表为空时任何策略都救不了。

组件职责
Directory持有当前可用 Invoker 列表(随注册通知更新)
Router按规则过滤/排序列表(机房、标签、方法、参数)
LoadBalance在过滤后的列表里选一个
Cluster组织一次「逻辑调用」:是否重试、是否并行、是否吞掉异常

可以把它想成:Directory 是菜单,Router 是忌口,LoadBalance 是点菜,Cluster 是「这道菜糊了是否换一家重做」。

2. 容错策略:失败之后怎么办

策略行为适用
Failover失败换其他实例重试(默认常带 retries)幂等读;写路径危险
Failfast一次失败立即抛错非幂等写、要快速失败
Failsafe失败吞掉,返回空/默认审计、日志类「失败可忽略」
Failback失败后台定时重试消息类、最终补偿
Forking并行调多个,一个成功即返回对延迟极度敏感的读,成本高
Broadcast逐个调用全部,任一下失败则失败通知刷新缓存等

2.1 为什么默认 Failover 会害死人

Failover 的隐藏乘数:

下游超时 ≈ 100ms,retries=2 → 调用方可能等 300ms+,且故障时 QPS 近似 ×(1+retries)。

竞价链路总 deadline 若只有 150–200ms,一次 Failover 就能吃光盘,并拖垮更多线程。这与 RPC 开篇 的「无脑重试放大」同一故事。

铁律

3. 负载均衡

常见负载均衡策略示意。四个面板:Random 加权随机;RoundRobin 轮询;LeastActive 优先活跃请求少的节点;ConsistentHash 同参数落到同节点。底部注:路由过滤后的列表才是 LB 输入。

3.1 Random(加权随机)

默认常见选择。权重高的实例命中概率高;实现简单、分散性好。权重来自注册元数据或动态配置——发布时把新版本权重从 0 爬升,是一种朴素金丝雀。

3.2 RoundRobin(加权轮询)

更平滑的序列感;在权重变更、列表频繁变动时要实现正确的加权轮询,边界比随机多。

3.3 LeastActive(最少活跃)

优先选「正在处理中的请求更少」的实例——对快慢不均的集群更公平。注意活跃数统计的是客户端视角的 in-flight,不是 Provider CPU;慢节点会自然少接新请求。

3.4 ConsistentHash(一致性哈希)

按参数(如 userId)把请求粘到同一节点。适合缓存亲和、会话亲和;节点增减会扰动映射(虚拟节点缓解但不消除)。别把一致性哈希当成「顺序保证」——那是业务语义,不是 LB 承诺。

3.5 均匀性的幻觉

「不均」常见原因:

  1. 路由后只剩少数候选;
  2. 权重差异大;
  3. 粘滞连接;
  4. 部分实例刚上线、预热未完成;
  5. 客户端少、样本不足(小流量看随机本就不平)。

4. 路由:灰度与单元化的主杠杆

路由发生在 LB 之前:先裁剪,再选择。

4.1 条件路由(Condition)

形如:

method=deduct => region=unit-a
consumer.application=bidder => tag=gray

用消费者属性、方法名、附件参数匹配,收窄 Provider 集合。匹配过严会导致过滤后为空——表现仍是 No provider,但根因在规则而非注册。

4.2 标签路由(Tag)

给 Provider 打 tag=gray,Consumer 带同一 tag 优先/强制命中。适合金丝雀与平行试验流量。记住:无 tag 的存量流量怎么回落(是否允许打到无 tag 节点)必须显式规定,否则灰度节点会被「不相关流量」冲垮,或灰度流量掉进基线。

4.3 脚本路由

灵活但危险——脚本缺陷可以瞬间把流量引到错误集合。生产环境应平台托管、评审、可快速回滚。

5. 粘滞、分区与可用区亲和

6. 与超时、线程池的耦合

Cluster 策略不是孤立旋钮:

旋钮与 Cluster 的互动
timeoutFailover 总耗时 ≈ 单次超时 × 尝试次数
retries直接决定放大倍数
actives / 连接限制限制单机压力,和 LeastActive 互补
线程池Provider 打满时,换节点重试可能「毒打」整个集群

经验:先定 deadline,再反推单次 timeout 与最大尝试次数,最后才选 loadbalance 名字。

7. AdTech 配置样板

扣预算(写,非幂等)

cluster=failfast
retries=0
timeout=50
loadbalance=leastactive

拉用户画像(读,可幂等)

cluster=failover
retries=1
timeout=40
loadbalance=random

并配合:业务幂等键、单元路由、发布窗口关闭长重试。

8. 生产反模式

9. 常见误解 ↔ 正解

常见误解正解
Failover 更「高可用」对非幂等写,它更「高危」
Random 一定不均匀大样本下可接受;不均先查权重/路由
路由是运维可选项单元化/灰度下它是正确性的一部分
Cluster 能掩盖错误地址列表全是僵尸时换谁都超时
最少活跃=最空闲 CPU是客户端 in-flight,不是主机监控

10. 速查表

下一篇钻到字节层——协议栈与 Triple / 序列化:经典 Dubbo 协议与基于 HTTP/2 的 Triple 如何承载一次 Invocation。


延伸阅读

本系列内部串读:

相关:

一手资料:


views
Share this post on:

Previous Post
Dubbo 深挖 · 协议栈与 Triple / 序列化
Next Post
Dubbo 深挖 · 注册中心、服务发现与元数据