前言

在微服务架构中,服务间的依赖关系复杂且动态,任何一个服务的故障都可能引发连锁反应,导致系统雪崩。一个好的容错设计可以避免这些问题发生:

  • 服务雪崩效应:单个服务崩溃或响应延迟可能导致调用链上的所有服务被阻塞,最终拖垮整个系统。例如,若服务 A 依赖服务 B,而服务 B 因高负载无法响应,A 的线程池可能被占满,进而影响其他依赖A的服务;

  • 分布式系统的脆弱性:网络抖动、节点宕机、资源耗尽等问题在分布式环境中不可避免。容错机制通过冗余和快速失败策略,确保部分故障不会扩散到整个系统;

  • 服务的可用性低:微服务的目标是提升系统可用性,而容错设计(如故障转移、熔断)是保障服务持续可用的核心手段。例如,通过自动切换健康节点,避免单点故障。

Dubbo 的集群容错机制

在 Dubbo 中,多个 Provider 实例构成一个「集群」。消费者调用时,Dubbo 通过 Cluster 模块实现容错策略的封装和路由,Cluster 模块会根据配置(如 cluster=failover)装配不同的容错策略实现类,对 Directory 中的多个 Invoker 进行处理,返回一个可执行的 Invoker。Dubbo 当前已支持以下 6 种容错策略(在 org.apache.dubbo.rpc.cluster.support 包下):

策略简称 实现类名 特性 使用场景
Failover FailoverClusterInvoker 失败自动重试,默认实现 网络不稳定,民登操作
Failfast FailfastClusterInvoker 快速失败,不重试 响应时间敏感,非幂等
Failsafe FailsafeClusterInvoker 失败忽略异常 日志记录、监控等非主要场景
Failback FailbackClusterInvoker 失败后后台重试 可容忍失败,后续补偿重试
Forking ForkingClusterInvoker 并行调用多个节点,最快成功返回 实时性要求高,资源充足
Broadcast BroadcastClusterInvoker 广播方式调用所有服务提供着 配置更新、通知类等操作

Failover Cluster(失败自动切换,默认策略)

实现原理:通过循环重试实现容错。

实现源码关键点:

  1. FailoverClusterInvoker 的 doInvoke 方法中,通过 for 循环控制重试次数(默认重试 2 次,共调用 3 次);
  2. 每次重试前调用 list(invocation) 重新获取最新的 Invoker 列表,确保动态感知节点变化。
// 代码片段:org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker#doInvoke
for (int i = 0; i < len; i++) {
if (i > 0) {
copyInvokers = list(invocation); // 动态刷新 Invoker 列表
}
Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);
// 调用并处理异常...
}

Failfast Cluster(快速失败)

实现原理:仅发起一次调用,异常直接抛出。

实现源码关键点:

  1. FailfastClusterInvoker 直接调用目标 Invoker,不进行重试。
// 代码片段:org.apache.dubbo.rpc.cluster.support.FailfastClusterInvoker#doInvoke
fpublic Result doInvoke(...) throws RpcException {
checkInvokers(invokers, invocation);
Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
return invoker.invoke(invocation); // 仅一次调用
}

Failsafe Cluster(失败安全)

实现原理:异常被捕获后返回空结果,不中断流程。

实现源码关键点:

  1. ailsafeClusterInvoker通过try-catch捕获异常并记录日志。
// 代码片段:org.apache.dubbo.rpc.cluster.support.FailsafeClusterInvoker
try {
// 调用逻辑...
} catch (Throwable e) {
logger.error("Failsafe ignore exception", e);
return new RpcResult(); // 返回空结果
}

Failback Cluster(失败自动恢复)

实现原理:失败请求存入队列,定时重试。

实现源码关键点:

  1. 捕获失败异常,使用 RetryTimerTask 存储失败请求,定时触发重试。
// 代码片段:org.apache.dubbo.rpc.cluster.support.FailbackClusterInvoker#doInvoke
private void addFailed(
LoadBalance loadbalance,
Invocation invocation,
List<Invoker<T>> invokers,
Invoker<T> lastInvoker,
URL consumerUrl) {
if (failTimer == null) {
synchronized (this) {
if (failTimer == null) {
failTimer = new HashedWheelTimer(
new NamedThreadFactory("failback-cluster-timer", true),
1,
TimeUnit.SECONDS,
32,
failbackTasks);
}
}
}
RetryTimerTask retryTimerTask = new RetryTimerTask(
loadbalance, invocation, invokers, lastInvoker, retries, RETRY_FAILED_PERIOD, consumerUrl);
try {
failTimer.newTimeout(retryTimerTask, RETRY_FAILED_PERIOD, TimeUnit.SECONDS);
} catch (Throwable e) {
logger.error(
CLUSTER_TIMER_RETRY_FAILED,
"add newTimeout exception",
"",
"Failback background works error, invocation->" + invocation + ", exception: " + e.getMessage(),
e);
}
}

Forking Cluster(并行调用)

实现原理:并发调用多个节点,首个成功结果即返回。

实现源码关键点:

  1. 使用线程池并发调用,结果通过 BlockingQueue 异步接收。
// 代码片段:org.apache.dubbo.rpc.cluster.support.ForkingClusterInvoker#doInvoke
for (Invoker<T> invoker : selected) {
executor.execute(() -> {
Result result = invoker.invoke(invocation);
ref.offer(result); // 结果存入队列
});
}

Broadcast Cluster(广播调用)

实现原理:逐个调用所有节点,任一失败则整体失败。

实现源码关键点:

  1. 遍历所有 Invoker 调用,异常累积后抛出。
// 代码片段:org.apache.dubbo.rpc.cluster.support.BroadcastClusterInvoker#doInvoke
for (Invoker<T> invoker : invokers) {
try {
invoker.invoke(invocation);
} catch (RpcException e) {
exception = e;
}
}
if (exception != null) throw exception;

如何自定义集群容错策略

如果以上提供的容错策略不满足需求,Dubbo 支持通过 SPI 自定义 Cluster 实现,步骤如下:

第一步:实现 Cluster 和 AbstractClusterInvoker
@SPI("custom")
public class MyCluster implements Cluster { @Override
public <T> Invoker<T> join(Directory<T> directory) {
return new MyClusterInvoker<>(directory);
} }
public class MyClusterInvoker<T> extends AbstractClusterInvoker<T> {

    @Override
protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) {
// 自定义逻辑,例如条件重试、动态路由等
} }
第二步:添加 SPI 配置

META-INF/dubbo/org.apache.dubbo.rpc.cluster.Cluster 中添加配置:

mycluster=com.example.MyCluster
第三步:配置使用自定义容错策略
<dubbo:reference cluster="mycluster" />

总结

建议核心服务优先使用 Failover(失败自动切换) 策略保障可用性,非核心服务可降级为 Failsafe(失败安全)。同时结合 Hystrix(已停止更新)Sentinel 实现熔断与限流,增强容错能力。

通过灵活组合 Dubbo 的容错策略,可显著提升分布式系统的鲁棒性。实际应用配置时需要根据业务特性权衡延迟、资源开销与一致性要求,一切皆是 trade off ~

P.S. 不妨再深入思考一下:Dubbo 的集群容错实现中有哪些优秀设计值得我们学习?

Dubbo 中的集群容错的更多相关文章

  1. Dubbo之旅--集群容错和负载均衡

    当我们的系统中用到Dubbo的集群环境,由于各种原因在集群调用失败时,Dubbo提供了多种容错方案,缺省为failover重试. Dubbo的集群容错在这里想说说他是由于我们实际的项目中出现了此类的问 ...

  2. Dubbo 源码分析 - 集群容错之 Cluster

    1.简介 为了避免单点故障,现在的应用至少会部署在两台服务器上.对于一些负载比较高的服务,会部署更多台服务器.这样,同一环境下的服务提供者数量会大于1.对于服务消费者来说,同一环境下出现了多个服务提供 ...

  3. dubbo源码解析五 --- 集群容错架构设计与原理分析

    欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 博客园 Dubbo 入门之二 --- 项目结构解析 博客园 Dubbo 源码分析系列之 ...

  4. Dubbo学习笔记7:Dubbo的集群容错与负载均衡策略

    Dubbo的集群容错策略 正常情况下,当我们进行系统设计时候,不仅要考虑正常逻辑下代码该如何走,还要考虑异常情况下代码逻辑应该怎么走.当服务消费方调用服务提供方的服务出现错误时候,Dubbo提供了多种 ...

  5. Dubbo学习(二) Dubbo 集群容错模式-负载均衡模式

    Dubbo是Alibaba开源的分布式服务框架,我们可以非常容易地通过Dubbo来构建分布式服务,并根据自己实际业务应用场景来选择合适的集群容错模式,这个对于很多应用都是迫切希望的,只需要通过简单的配 ...

  6. Dubbo的集群容错与负载均衡策略及自定义(一致性哈希路由的缺点及自定义)

    Dubbo的集群容错策略 正常情况下,当我们进行系统设计时候,不仅要考虑正常逻辑下代码该如何走,还要考虑异常情况下代码逻辑应该怎么走.当服务消费方调用服务提供方的服务出现错误时候,Dubbo提供了多种 ...

  7. Dubbo 系列(07-4)集群容错 - 集群

    BDubbo 系列(07-4)集群容错 - 集群 [toc] Spring Cloud Alibaba 系列目录 - Dubbo 篇 1. 背景介绍 相关文档推荐: Dubbo 集群容错 - 实战 D ...

  8. Dubbo 系列(07-3)集群容错 - 负载均衡

    目录 Dubbo 系列(07-3)集群容错 - 负载均衡 Spring Cloud Alibaba 系列目录 - Dubbo 篇 1. 背景介绍 1.1 负载均衡算法 1.2 继承体系 2. 源码分析 ...

  9. Dubbo的集群容错与负载均衡策略

    Dubbo的集群容错策略 正常情况下,当我们进行系统设计时候,不仅要考虑正常逻辑下代码该如何走,还要考虑异常情况下代码逻辑应该怎么走.当服务消费方调用服务提供方的服务出现错误时候,Dubbo提供了多种 ...

  10. 基于Dubbo框架构建分布式服务(集群容错&负载均衡)

    Dubbo是Alibaba开源的分布式服务框架,我们可以非常容易地通过Dubbo来构建分布式服务,并根据自己实际业务应用场景来选择合适的集群容错模式,这个对于很多应用都是迫切希望的,只需要通过简单的配 ...

随机推荐

  1. c# Lamda表达式 简化语法例子

    看到一个老代码里的方法,是判断两个string 数组是否存在相同的元素: 快一百行代码了..... public bool HasRole(string[] roleList) { bool resu ...

  2. MakeFile简单示例

    简单的Makefile编写学了会点,不学又忘了.这里参考了多位大佬的Makefile教程,自己给自己写的示例,如有错误请告知一下我. #version 1//最简单,没难度 hello : main. ...

  3. uni-app中picker-view显示默认值的注意点(坑)

    今天我在使用picker-view的时候,发现无法给picker-view给一个默认值:后面经过发现后: 才知道到,是一个异步问题: 1==>动态循环出来的数据,在data中直接循环,不要在re ...

  4. pkill 踢出某个终端

    是ps命令和kill命令的结合,按照进程名来杀死指定进程 选项 -o:仅向找到的最小(起始)进程号发送信号: -n:仅向找到的最大(结束)进程号发送信号: -P:指定父进程号发送信号: -g:指定进程 ...

  5. linux--notepad++安装

      通过PPA进行安装notepad++ sudo add-apt-repository ppa:notepadqq-team/notepadqq sudo apt-get update sudo a ...

  6. Microsoft.Expression.Drawing文件安装

    使用Blend的绘制功能,需要引用 Microsoft.Expression.Drawing 库文件, xmlns:ed="http://schemas.microsoft.com/expr ...

  7. 自助式BI:灵活应变的商业智能

    在这个信息爆炸的时代,商业智能(BI)已经成为企业决策的必备工具.无论是哪个行业,哪个规模的企业,似乎都无法忽视这一强大工具的存在.然而,传统的BI模式往往存在着一些限制,使得企业无法灵活地应对各种业 ...

  8. ingsollrang英格索兰IC直流电动拧紧控制器维修

    随着智能装配的概念逐渐在行业内推广,质量管理已成为实现智能装配过程中的一个重要环节,许多客户都有着数据记录.扭矩检测的需求,英格索兰的多种拧紧工具配合控制器,可以满足从基本拧紧到质量管理的一系列需求, ...

  9. 【忍者算法】从生活到代码:解密链表大数相加的美妙算法|LeetCode第2题"两数相加"

    从生活到代码:解密链表大数相加的美妙算法 从超市收银说起 想象你是一个超市收银员,正在计算两位顾客的购物总和.每位顾客的商品都按照从个位到高位的顺序摆放(比如54元就是先放4元商品,再放50元商品). ...

  10. Processing 使用pixels[]像素数组绘制矩形rect和圆形ellipse

    余温 两次绘制了棋盘格,有了一些经验了,顺着学习态势,我们再接再厉,挖一些技巧.这一次要使用pixels[]数组绘制矩形rect和圆形ellipse,也就是代替rect()和ellipse()两个函数 ...