dubbo集羣容錯策略的代碼分析3

接上篇http://www.javashuo.com/article/p-awxzbqol-ce.htmljava

dubbo 版本2.5.3負載均衡

經過代碼能夠看到failback,failover,failsafe,forking,failfast都經過了父類的select方法選擇服務提供者(invoker)
這個方法裏,也包含有dubbo處理集羣的機制,包括使用負載均衡的策略。通知能夠看到available和broadcast方案目前沒用到負載均衡策略,先看先看select方法url

/**
     * 使用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方法.net

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的從新選擇。在看,重選方法:code

/**
     * 重選,先從非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;
    }

這個方法,就是實現儘可能不從已選列表中選擇invokerblog

dubbo負載均衡http://www.javashuo.com/article/p-fjpmnwyl-db.htmlget

相關文章
相關標籤/搜索