接上篇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