dubbo負載均衡代碼分析3(加權輪詢策略)

接上篇http://www.javashuo.com/article/p-kxvfgusz-ez.htmljava

加權輪詢,我第一次沒理解,我的以爲很差理解。因而先仿照源碼抽象出邏輯模型,代碼以下:算法

public static void main(String[] args) {
        //存儲調用的方法和總的調用次數的map
         final ConcurrentMap<String, AtomicInteger> sequences = new ConcurrentHashMap<String, AtomicInteger>();
        //統計invoker 被調用次數map
         final ConcurrentMap<String, AtomicInteger> result = new ConcurrentHashMap<String, AtomicInteger>();
        //模擬方法三個invoker 分別爲 a,b,c
        List<String> invokes=new ArrayList<String>(3);
        invokes.add("a");
        invokes.add("b");
        invokes.add("c");
        //存儲invoker和權重的對應map
        final LinkedHashMap<String, AtomicInteger> invokerToWeightMap = new LinkedHashMap<String,AtomicInteger>();
         for(int i=0;i<21;i++){
             //每次調用都把模擬的權重從新放入
             invokerToWeightMap.put("a",new AtomicInteger(3));
             invokerToWeightMap.put("b",new AtomicInteger(6));
             invokerToWeightMap.put("c",new AtomicInteger(9));
             select(invokes,invokerToWeightMap,sequences,result);
         }
        //打印調用結果統計
         for(Map.Entry<String, AtomicInteger> r : result.entrySet()){
             System.out.println(r.getKey()+"被調用:"+r.getValue()+"次");
         }
        }

    private  static void  select(List<String> invokes,
                                 LinkedHashMap<String, AtomicInteger> invokerToWeightMap,
                                 ConcurrentMap<String, AtomicInteger> sequences,
                                 ConcurrentMap<String, AtomicInteger> result){
       //假設調用servcie.hello方法
        AtomicInteger sequence = sequences.get("service.hello");
        if (sequence == null) {
            //默認調用次數爲0
            sequences.putIfAbsent("servcie.hello", new AtomicInteger(0));
            sequence = sequences.get("servcie.hello");
        }
        //調用次數+1
        int currentSequence = sequence.getAndIncrement();
        System.out.print("currentSequence:" + currentSequence);
        int maxWeight=9;//最大權重
        int minWeight=3;//最小權重
        int weightSum=18;//總權重
        if (maxWeight > 0 && minWeight < maxWeight) { // 走權重不同邏輯。
            int mod = currentSequence % weightSum;
            System.out.print(" mod:" + mod);
            for (int i = 0; i < maxWeight; i++) {
                for (Map.Entry<String, AtomicInteger> each : invokerToWeightMap.entrySet()) {
                    final String k = each.getKey();
                    final AtomicInteger v = each.getValue();
                    if (mod == 0 && v.intValue() > 0) {
                        System.out.println(" selected:"+k);
                        AtomicInteger count = result.get(k);
                        if (count == null) {
                            result.putIfAbsent(k, new AtomicInteger(1));
                        }else{
                            count.incrementAndGet();
                        }
                        return;
                    }
                    if (v.intValue() > 0) {
                        v.decrementAndGet();
                        mod--;
                    }
                }
            }
        }

    }

輸出結果,分析:app

currentSequence:0 mod:0 selected:a
currentSequence:1 mod:1 selected:b
currentSequence:2 mod:2 selected:c
currentSequence:3 mod:3 selected:a
currentSequence:4 mod:4 selected:b
currentSequence:5 mod:5 selected:c
currentSequence:6 mod:6 selected:a
currentSequence:7 mod:7 selected:b
currentSequence:8 mod:8 selected:c
//前9次調用一直是簡單輪詢
currentSequence:9 mod:9 selected:b
currentSequence:10 mod:10 selected:cthis

currentSequence:11 mod:11 selected:b
currentSequence:12 mod:12 selected:curl

currentSequence:13 mod:13 selected:b
currentSequence:14 mod:14 selected:c
//10到16次調用只在b c間輪詢
currentSequence:15 mod:15 selected:c
currentSequence:16 mod:16 selected:c
currentSequence:17 mod:17 selected:c
//17到19次調用只調c
currentSequence:18 mod:0 selected:a
currentSequence:19 mod:1 selected:b
currentSequence:20 mod:2 selected:c
//因爲mod取值歸零,20到21次新一輪的輪詢
最後調用總結:
a被調用:4次
b被調用:7次
c被調用:10次.net

體現出加權輪詢,這就是duboo的加權輪詢算法。code

理解上面的代碼,再看源代碼,就容易理解不少。
源碼以下:blog

public static final String NAME = "roundrobin";

    private final ConcurrentMap<String, AtomicPositiveInteger> sequences = new ConcurrentHashMap<String, AtomicPositiveInteger>();

    protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
        String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName();
        int length = invokers.size(); // 總個數
        int maxWeight = 0; // 最大權重
        int minWeight = Integer.MAX_VALUE; // 最小權重
        final LinkedHashMap<Invoker<T>, IntegerWrapper> invokerToWeightMap = new LinkedHashMap<Invoker<T>, IntegerWrapper>();
        int weightSum = 0;
        for (int i = 0; i < length; i++) {
            int weight = getWeight(invokers.get(i), invocation);
            maxWeight = Math.max(maxWeight, weight); // 累計最大權重
            minWeight = Math.min(minWeight, weight); // 累計最小權重
            if (weight > 0) {
                invokerToWeightMap.put(invokers.get(i), new IntegerWrapper(weight));
                weightSum += weight;
            }
        }
        AtomicPositiveInteger sequence = sequences.get(key);
        if (sequence == null) {
            sequences.putIfAbsent(key, new AtomicPositiveInteger());
            sequence = sequences.get(key);
        }
        //總的調用次數
        int currentSequence = sequence.getAndIncrement();
        if (maxWeight > 0 && minWeight < maxWeight) { // 權重不同
            //取模操做,保證mod值域在[0,weightSum)
            int mod = currentSequence % weightSum;
            for (int i = 0; i < maxWeight; i++) {//maxWeight選最大權重,保證加上子循環
               // 即 maxWeight*(invoker個數)>mod 值。這個mod就能夠減到0
                for (Map.Entry<Invoker<T>, IntegerWrapper> each : invokerToWeightMap.entrySet()) {
                    final Invoker<T> k = each.getKey();
                    final IntegerWrapper v = each.getValue();
                    //在一次選擇過程後(mod--,權重--,mod==0結束),選下一個權重大於0的
                    if (mod == 0 && v.getValue() > 0) {
                        return k;
                    }
                    if (v.getValue() > 0) {
                        //基於mod,來講以前選過的,權重-1.mod--
                        v.decrement();
                        mod--;
                    }
                }
            }
        }
        // 權重同樣   取模輪循 簡單輪詢
        return invokers.get(currentSequence % length);
    }

    private static final class IntegerWrapper {
        private int value;

        public IntegerWrapper(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }

        public void setValue(int value) {
            this.value = value;
        }

        public void decrement() {
            this.value--;
        }
    }

我理解,這個算法的思想,就是讓權重小的候選者,經過-1 老是很快較早的不參與某個輪次的選擇。ci

相關文章
相關標籤/搜索