本文是Dubbo集群的最厚一部分内容,之前的博客中介绍了Dubbo使用服务目录获取可用的Provider,然后通过服务路由得到符合配置的Provider,然后通过负载均衡算法选出最佳的Provider,对该Provider发起RPC调用。但是RPC调用并不是一定成功的,那么如何处理调用失败呢?这就是本文将要讨论的内容,Dubbo中的集群容错策略。

集群容错简介

集群容错是指,当rpc调用失败时,处理这个调用失败所采用的机制。Dubbo中共提供了九种容错机制,下面是一个总结:

容错策略优点缺点应用场景
Failover,调用失败自动重试调用成功率高调用RT变长对调用rt不敏感的场景
Failfast,失败后抛出给上层业务可以快速感知到调用失败业务需要自行处理报错由业务处理掉用失败的场景
Failsafe,不处理失败不会报错报错不会抛出,需要自行监控非核心链路
Failback,异步重试自动异步重试集群不稳定时,重试任务会堆积实时性要求低
Forking,并行发起多个调用调用成功率高消耗资源,需要保证幂等资源充足,实时性要求高
Broadcast,对所有Provider发起调用可以对所有Provider发起调用消耗资源通知所有Provider执行某项操作
Available,只调用一个可用的Invoker不使用负载均衡,业务可以快速感知到失败业务自行处理报错,调用的Invoker可能不是当前最优的不需要负载均衡
Mergeable,组合多个Invoker的调用结果将一次请求拆分成多个需要发起多次RPC调用与Group配合使用,通过分组对调用结果进行组合

集群容错源码分析

本文以Dubbo默认的集群容错进行分析,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
    // ..
    // 从调用参数中获取充实次数
    int len = calculateInvokeTimes(methodName);
    // retry loop.
    RpcException le = null; // last exception.
    List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyInvokers.size()); // invoked invokers.
    Set<String> providers = new HashSet<>(len);
    for (int i = 0; i < len; i++) {
        // 在第一次调用之后,每次都检查Invoker,防止出现变更
        if (i > 0) {
            checkWhetherDestroyed();
            copyInvokers = list(invocation);
            // check again
            checkInvokers(copyInvokers, invocation);
        }
        // 进行负载均衡选出合适的Invoker
        Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);
        invoked.add(invoker);
        RpcContext.getServiceContext().setInvokers((List) invoked);
        boolean success = false;
        // 开始调用,调用成功则直接返回, 失败则进行下次调用
        try {
            Result result = invokeWithContext(invoker, invocation);
            if (le != null && logger.isWarnEnabled()) {
                logger.warn(/** ... **/);
            }
            success = true;
            return result;
        } catch (RpcException e) {
            if (e.isBiz()) { // biz exception.
                throw e;
            }
            le = e;
        } catch (Throwable e) {
            le = new RpcException(e.getMessage(), e);
        } finally {
            if (!success) {
                providers.add(invoker.getUrl().getAddress());
            }
        }
    }
    throw new RpcException(/** ... **/);
}

总结

本文介绍了Dubbo中提供的集群容错策略,并分析了默认的集群容错策略的源码。

参考文献

  1. 集群容错 | Apache Dubbo
  2. dubbo系列四、dubbo集群容错和负载均衡 - 不晓得侬 - 博客园