专栏首页wannshan(javaer,RPC)dubbo集群容错策略的代码分析3

dubbo集群容错策略的代码分析3

接上篇 https://cloud.tencent.com/developer/article/1109591

dubbo 版本2.5.3

通过代码可以看到failback,failover,failsafe,forking,failfast都通过了父类的select方法选择服务提供者(invoker) 这个方法里,也包含有dubbo处理集群的机制,包括使用负载均衡的策略。通知可以看到available和broadcast方案目前没用到负载均衡策略,先看先看select方法

/**
     * 使用loadbalance选择invoker.</br>
     * a)先lb选择,如果在selected列表中 或者 不可用且做检验时,进入下一步(重选),否则直接返回</br>
     * b)重选验证规则:selected > available .保证重选出的结果尽量不在select中,并且是可用的
     *
     * @param availablecheck 如果设置true,在选择的时候先选invoker.available == true
     * @param selected       已选过的invoker.注意:输入保证不重复
     */
    protected Invoker<T> select(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected) throws RpcException {
        if (invokers == null || invokers.size() == 0)
            return null;
        String methodName = invocation == null ? "" : invocation.getMethodName();
         //是否启用sticky 粘性连接,让客户端总是连接同一提供者
        boolean sticky = invokers.get(0).getUrl().getMethodParameter(methodName, Constants.CLUSTER_STICKY_KEY, Constants.DEFAULT_CLUSTER_STICKY);
        {
            //ignore overloaded method
            //可选提供者列表已不包含,上次的stickyInvoker,设置为null

            if (stickyInvoker != null && !invokers.contains(stickyInvoker)) {
                stickyInvoker = null;
            }
            //ignore cucurrent problem
            //stickyInvoker不为null,并且没在已选列表中,返回上次的服务提供者stickyInvoker,但之前强制校验可达性。
	    //由于stickyInvoker不能包含在selected列表中,通过代码看,可以得知forking和failover集群策略,用不了sticky属性
            if (sticky && stickyInvoker != null && (selected == null || !selected.contains(stickyInvoker))) {
                if (availablecheck && stickyInvoker.isAvailable()) {
                    return stickyInvoker;
                }
            }
        }
        //利用负载均衡选一个提供者
        Invoker<T> invoker = doselect(loadbalance, invocation, invokers, selected);

        if (sticky) {
            stickyInvoker = invoker;
        }
        return invoker;
    }

这个方法实现里,包含了dubbo的sticky特性的实现,看下doselect方法

private Invoker<T> doselect(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected) throws RpcException {
        if (invokers == null || invokers.size() == 0)
            return null;
        //只有一个,不用选了,直接返回
        if (invokers.size() == 1)
            return invokers.get(0);
        //如果只有两个invoker,退化成轮循
        if (invokers.size() == 2 && selected != null && selected.size() > 0) {
            return selected.get(0) == invokers.get(0) ? invokers.get(1) : invokers.get(0);
        }
        //大于两个,利用负载均衡选择一个
        Invoker<T> invoker = loadbalance.select(invokers, getUrl(), invocation);

        //如果选择的提供者,已在selected中包含(优先判断) 或者
        // 不可用&&availablecheck=true
        // 则重新选择
        if ((selected != null && selected.contains(invoker))
                || (!invoker.isAvailable() && getUrl() != null && availablecheck)) {
            try {
                //重新选择
                Invoker<T> rinvoker = reselect(loadbalance, invocation, invokers, selected, availablecheck);
                if (rinvoker != null) {
                    invoker = rinvoker;
                } else {
                    //如果重新选择失败,看下第一次选的位置,如果不是最后,选+1位置.
                    int index = invokers.indexOf(invoker);
                    try {
                        //最后再避免碰撞
                        invoker = index < invokers.size() - 1 ? invokers.get(index + 1) : invoker;
                    } catch (Exception e) {
                        logger.warn(e.getMessage() + " may because invokers list dynamic change, ignore.", e);
                    }
                }
            } catch (Throwable t) {
                logger.error("clustor relselect fail reason is :" + t.getMessage() + " if can not slove ,you can set cluster.availablecheck=false in url", t);
            }
        }
        return invoker;
    }

这个方法里,处理了只有一个或者两个提供者的特殊情况和invoker的重新选择。在看,重选方法:

 /**
     * 重选,先从非selected的列表中选择,没有在从selected列表中选择.
     *
     * @param loadbalance
     * @param invocation
     * @param invokers
     * @param selected
     * @return
     * @throws RpcException
     */
    private Invoker<T> reselect(LoadBalance loadbalance, Invocation invocation,
                                List<Invoker<T>> invokers, List<Invoker<T>> selected, boolean availablecheck)
            throws RpcException {

        //预先分配一个,这个列表是一定会用到的.
        List<Invoker<T>> reselectInvokers = new ArrayList<Invoker<T>>(invokers.size() > 1 ? (invokers.size() - 1) : invokers.size());

        //先从非select中选
        //把不包含在已选列表中的提供者,放入重选列表reselectInvokers,让负载均衡器选择
        if (availablecheck) { //选isAvailable 的非select
            for (Invoker<T> invoker : invokers) {
                if (invoker.isAvailable()) {
                    if (selected == null || !selected.contains(invoker)) {
                        reselectInvokers.add(invoker);
                    }
                }
            }
            if (reselectInvokers.size() > 0) {
                return loadbalance.select(reselectInvokers, getUrl(), invocation);
            }
        } else { //选全部非select
            for (Invoker<T> invoker : invokers) {
                if (selected == null || !selected.contains(invoker)) {
                    reselectInvokers.add(invoker);
                }
            }
            if (reselectInvokers.size() > 0) {
                return loadbalance.select(reselectInvokers, getUrl(), invocation);
            }
        }
        //以上都没选择好,最后从select中选可用的. 
        {
            if (selected != null) {
                for (Invoker<T> invoker : selected) {
                    if ((invoker.isAvailable()) //优先选available
                            && !reselectInvokers.contains(invoker)) {
                        reselectInvokers.add(invoker);
                    }
                }
            }
            if (reselectInvokers.size() > 0) {
                return loadbalance.select(reselectInvokers, getUrl(), invocation);
            }
        }
        return null;
    }

这个方法,就是实现尽量不从已选列表中选择invoker

dubbo负载均衡 https://cloud.tencent.com/developer/article/1109586

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • dubbo基于spring运行原理解析

    dubbo是基于spring构建和运行的,兼容spring配置。这篇说说dubbo基于spring的过程。 dubbo首先利用了从spring2.0开始的一个...

    技术蓝海
  • dubbo路由机制代码分析1

    这回说说,dubbo路由特性,dubbo的路由干的事,就是一个请求过来, dubbo依据配置的路由规则,计算出哪些提供者可以提供这次的请求服务。 所以,它的...

    技术蓝海
  • dubbo监控机制之监控中心实现分析

    github 地址 https://github.com/apache/dubbo-admin ,被单独移到dubbo-admin中维护,在master 分支中

    技术蓝海
  • LinkedList的实现原理浅析

    查看LinkedList的源码,发现其继承自AbstractSequentialList,实现了List,Deque,Cloneable以及Serializab...

    孟君
  • dubbo基于spring运行原理解析

    dubbo是基于spring构建和运行的,兼容spring配置。这篇说说dubbo基于spring的过程。 dubbo首先利用了从spring2.0开始的一个...

    技术蓝海
  • Android网络之HttpUrlConnection和Socket关系解析

    多年以前Android的网络请求只有Apache开源的HttpClient和JDK的HttpUrlConnection,近几年随着OkHttp的流行Androi...

    静默加载
  • Mysql的 If和 Case语句

    比如在上例子中,我们存储了一些不希望暴露性别的用户,存储的值为3.此时想要查询可以:

    呼延十
  • Android5.0以上版本录屏实现代码(完整代码)

    我录屏的方式是分别录制音频和视频,最后合并成mp4格式,比较麻烦,因为网上完整的教程比较少,所以我打算写一个完整版的,照着我的代码写完之后,至少是能够实现功能的...

    砸漏
  • Java 集合深入理解(17):HashMap 在 JDK 1.8 后新增的红黑树结构

    上篇文章我们介绍了 HashMap 的主要特点和关键方法源码解读,这篇文章我们介绍 HashMap 在 JDK1.8 新增树形化相关的内容。 传统 HashMa...

    张拭心 shixinzhang
  • 编程的智慧

    编程是一种创造性的工作,是一门艺术。精通任何一门艺术,都需要很多的练习和领悟,所以这里提出的“智慧”,并不是号称一天瘦十斤的减肥药,它并不能代替你自己的勤奋。然...

    老钱

扫码关注云+社区

领取腾讯云代金券