Dubbo 源码解析07_Dubbo 重试机制

Posted 快鸟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dubbo 源码解析07_Dubbo 重试机制相关的知识,希望对你有一定的参考价值。

Dubbo 重试机制

通过前面 Dubbo 服务发现&引用 的分析,我们知道,Dubbo 的重试机制是通过 com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker 来实现的:

public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
    List<Invoker<T>> copyinvokers = invokers;
    checkInvokers(copyinvokers, invocation);
    // 默认重试 2 次
    int len = getUrl().getMethodParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1;
    if (len <= 0) {
        len = 1;
    }
    // retry loop.
    RpcException le = null; // last exception.
    List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyinvokers.size()); // invoked invokers.
    Set<String> providers = new HashSet<String>(len);
    for (int i = 0; i < len; i++) {
        //Reselect before retry to avoid a change of candidate `invokers`.
        //NOTE: if `invokers` changed, then `invoked` also lose accuracy.
        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.getContext().setInvokers((List) invoked);
        try {
            Result result = invoker.invoke(invocation);
            if (le != null && logger.isWarnEnabled()) {
                logger.warn("Although retry the method " + invocation.getMethodName()
                        + " in the service " + getInterface().getName()
                        + " was successful by the provider " + invoker.getUrl().getAddress()
                        + ", but there have been failed providers " + providers
                        + " (" + providers.size() + "/" + copyinvokers.size()
                        + ") from the registry " + directory.getUrl().getAddress()
                        + " on the consumer " + NetUtils.getLocalHost()
                        + " using the dubbo version " + Version.getVersion() + ". Last error is: "
                        + le.getMessage(), le);
            }
            return result;
        } catch (RpcException e) {
            if (e.isBiz()) { // biz exception.
                throw e;
            }
            le = e;
        } catch (Throwable e) {
            le = new RpcException(e.getMessage(), e);
        } finally {
            providers.add(invoker.getUrl().getAddress());
        }
    }
    throw new RpcException(le != null ? le.getCode() : 0, "Failed to invoke the method "
            + invocation.getMethodName() + " in the service " + getInterface().getName()
            + ". Tried " + len + " times of the providers " + providers
            + " (" + providers.size() + "/" + copyinvokers.size()
            + ") from the registry " + directory.getUrl().getAddress()
            + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version "
            + Version.getVersion() + ". Last error is: "
            + (le != null ? le.getMessage() : ""), le != null && le.getCause() != null ? le.getCause() : le);
}

 

 

查看源码我们可以发现,dubbo 默认的重试次数是 2 次,也就是说,为了容错性,如果第一次调用出异常(非业务异常)的话,Dubbo 会重试其他的 Invoker 2 次(具体的重试算法请查看源码),如果还是失败的话,就抛出 RpcException。所以默认情况下,服务最多被调用 3 次。

 

注意:

  1. 这里的调用异常通常是指超时异常、网络异常等,具体可以查看 RpcException#isBiz() 方法

  2. 重试算法会优先重试 stickyInvoker,没有的话,会调用 LoadBalance 扩展来选择 Invoker。(具体实现请查看源码)

  

 

如果想了解更多Dubbo源码的知识,请移步 Dubbo源码解读——通向高手之路 的视频讲解:
http://edu.51cto.com/sd/2e565

 

以上是关于Dubbo 源码解析07_Dubbo 重试机制的主要内容,如果未能解决你的问题,请参考以下文章

dubbo源码分析7——dubbo的配置解析_与spring的整合

02.dubbo源码解析之Dubbo扩展点加载

dubbo源码解析

Dubbo源码分析之XML的Bean解析

Dubbo中SPI机制源码解析,这样学,面试必过

Dubbo架构设计与源码解析 服务注册