Nacos权重算法

权重算法

通过学习Nacos,在nacos中源码发现NamingService.selectOneHealthyInstance的权重算法。

基础含义
权重是一个相对的概念,是针对某一指标而言。某一指标的权重是指该指标在整体评价中的相对重要程度。

如:学生期末总评是对学生平时成绩,期中考成绩,期末考成绩的综合评价,但是这三个成绩所占期末总评的成绩的比重不一样。若平时成绩占30%,期中考成绩占30%,期末考成绩占40%,那么期末总评=平时成绩0.3+期中考成绩0.3+期末考成绩0.4。
  再打个比方说, 一件事情, 你给它打100分, 你的老板给它打60分, 如果平均, 则是(100+60)/2=80分. 但因为老板说的话分量比你重, 假如老板的权重是2, 你是1, 这时求平均值就是加权平均了, 结果是(100
1 + 602)/(1+2)=73.3分, 显然向你的老板那里倾斜了。假如老板权重是1,你的权重是3,结果是(1003+60*1)/(1+3)=90。这就是根据权重的不同进行的平均数的计算,所以又叫加权平均数

在源码中,我们发现 的方法是 refresh()以及randomWithWeight()

    protected static Instance getHostByRandomWeight(List<Instance> hosts) { 
        LogUtils.NAMING_LOGGER.debug("entry randomWithWeight");
        if (hosts != null && hosts.size() != 0) { 
            LogUtils.NAMING_LOGGER.debug("new Chooser");
            List<Pair<Instance>> hostsWithWeight = new ArrayList();
            Iterator var2 = hosts.iterator();

            while(var2.hasNext()) { 
                Instance host = (Instance)var2.next();
                if (host.isHealthy()) { 
                    hostsWithWeight.add(new Pair(host, host.getWeight()));
                }
            }

            LogUtils.NAMING_LOGGER.debug("for (Host host : hosts)");
            Chooser<String, Instance> vipChooser = new Chooser("www.taobao.com");
            vipChooser.refresh(hostsWithWeight);
            LogUtils.NAMING_LOGGER.debug("vipChooser.refresh");
            return (Instance)vipChooser.randomWithWeight();
        } else { 
            LogUtils.NAMING_LOGGER.debug("hosts == null || hosts.size() == 0");
            return null;
        }
    }
public void refresh() { 
            Double originWeightSum = 0.0D;
            Iterator var2 = this.itemsWithWeight.iterator();

            double weight;
            while(var2.hasNext()) { 
                Pair<T> item = (Pair)var2.next();
                weight = item.weight();
                if (weight > 0.0D) { 
                    this.items.add(item.item());
                    if (Double.isInfinite(weight)) { 
                        weight = 10000.0D;
                    }

                    if (Double.isNaN(weight)) { 
                        weight = 1.0D;
                    }

                    originWeightSum = originWeightSum + weight;
                }
            }

            double[] exactWeights = new double[this.items.size()];
            int index = 0;
            Iterator var10 = this.itemsWithWeight.iterator();

            double doublePrecisionDelta;
            while(var10.hasNext()) { 
                Pair<T> itemx = (Pair)var10.next();
                doublePrecisionDelta = itemx.weight();
                if (doublePrecisionDelta > 0.0D) { 
                    exactWeights[index++] = doublePrecisionDelta / originWeightSum;
                }
            }

            this.weights = new double[this.items.size()];
            weight = 0.0D;

            for(int i = 0; i < index; ++i) { 
                this.weights[i] = weight + exactWeights[i];
                weight += exactWeights[i];
            }

            doublePrecisionDelta = 1.0E-4D;
            if (index != 0 && Math.abs(this.weights[index - 1] - 1.0D) >= doublePrecisionDelta) { 
                throw new IllegalStateException("Cumulative Weight caculate wrong , the sum of probabilities does not equals 1.");
            }
        }
    public T randomWithWeight() { 
        Chooser<K, T>.Ref<T> ref = this.ref;
        double random = ThreadLocalRandom.current().nextDouble(0.0D, 1.0D);
        int index = Arrays.binarySearch(ref.weights, random);
        if (index < 0) { 
            index = -index - 1;
            return index >= 0 && index < ref.weights.length && random < ref.weights[index] ? ref.items.get(index) : ref.items.get(ref.items.size() - 1);
        } else { 
            return ref.items.get(index);
        }
    }

refresh()方法的主要作用是计算出一个数组,将每个权重的比例计算出来,如数组A[1,2,0,3],执行refresh(),去除小于等于0的数,得到B[1,2,3],再得到权重比例为[1/6,3/6,1]。至于为什么是3/6包含,可以看下

            this.weights = new double[this.items.size()];
            weight = 0.0D;

            for(int i = 0; i < index; ++i) { 
                this.weights[i] = weight + exactWeights[i];
                weight += exactWeights[i];
            }

可以发现,当i=1的时候,B[1]=A[0]+A[1]j,即1/6+2/6=3/6

理解到这里,作者当时存在疑惑,无论最后一个的权重是多大多小,都为1。这怎么就有根据权重算了?看到这里解除了我的疑惑

		//因为得到的B数组,肯定是大于0小于1,从0-1获取一个随机数
        double random = ThreadLocalRandom.current().nextDouble(0.0D, 1.0D);
        //根据二分法,查找到 random 的散落在0-1的范围
        int index = Arrays.binarySearch(ref.weights, random);

这时,我恍然大悟,原来 根据权重的算法,说到底,就是散落区间的概率。

    原文作者:良大大
    原文地址: https://blog.csdn.net/weixin_45396836/article/details/110927436
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞