按照权重负载的实现

常见的负载均衡的几种方式

  1. 随机
  2. 轮询
  3. hash
  4. 一致性hash
  5. 权重
  6. 最小链接
  7. 最短响应时间

今天先来看下dubbo怎么实现权重的负载均衡的,其实各种组件实现基本也一致,权重简单介绍下就是常见的设置,比如

server1 weight=1;
server2 weight=2;
server3 weight=1;

就是说现在来了100个请求,怎么能把对应的请求按照权重进行分配,server1占1/4 也就是分25个,server2一半,50个,server3 1/4 也就是25个
先看下dubbo怎么实现的,关键代码如下

protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
    String key = invokers.get(0).getUrl().getServiceKey() + "." + RpcUtils.getMethodName(invocation);
    ConcurrentMap<String, WeightedRoundRobin> map = ConcurrentHashMapUtils.computeIfAbsent(methodWeightMap, key, k -> new ConcurrentHashMap<>());
    int totalWeight = 0;
    long maxCurrent = Long.MIN_VALUE;
    long now = System.currentTimeMillis();
    Invoker<T> selectedInvoker = null;
    WeightedRoundRobin selectedWRR = null;
    // 所有的实例列表
    for (Invoker<T> invoker : invokers) {
        // 根据url得到的标识
        String identifyString = invoker.getUrl().toIdentityString();
        // 获取对应的权重
        int weight = getWeight(invoker, invocation);
        // 对应的权重类
        WeightedRoundRobin weightedRoundRobin = ConcurrentHashMapUtils.computeIfAbsent(map, identifyString, k -> {
            WeightedRoundRobin wrr = new WeightedRoundRobin();
            wrr.setWeight(weight);
            return wrr;
        });

        if (weight != weightedRoundRobin.getWeight()) {
            //weight changed
            weightedRoundRobin.setWeight(weight);
        }
        // 这里是每次遍历都要加上对应的权重,但是到后面选中的会减去,也就是大的都是需要被选中执行的
        long cur = weightedRoundRobin.increaseCurrent();
        weightedRoundRobin.setLastUpdate(now);
        if (cur > maxCurrent) {
            // maxCurrent就是在计算所有invoke里面的最大的cur,然后让其选中
            maxCurrent = cur;
            selectedInvoker = invoker;
            selectedWRR = weightedRoundRobin;
        }
        totalWeight += weight;
    }
    if (invokers.size() != map.size()) {
        map.entrySet().removeIf(item -> now - item.getValue().getLastUpdate() > RECYCLE_PERIOD);
    }
    if (selectedInvoker != null) {
        // 减去对应的值,下次如果不大于,totalWeight就是所有成员的总大小,
        selectedWRR.sel(totalWeight);
        return selectedInvoker;
    }
    // should not happen here
    return invokers.get(0);
}

大致总结下实现原理呢,就是把所有的服务提供者先列出来,放入到对应的map,有存储对应的服务者的权重信息,然后给其一个记录值 cur,然后每次遍历这些服务提供者,对其cur加上对应的权重值,然后找到cur最大的,选中让其执行,选中执行的,执行一次之后把对应的cur减去总的weight,举个例子,默认cur大家开始都是0,现在开始遍历
server1 cur = cur+weight;// cur = 1,
server2 cur = cur+weight;// cur=2
server3 cur = cur+weight; //cur=1
totalweight = server1的weight+server2的weight+server3的weight 就是4
这时候选中的就是服务2,然后服务2对应的cur 减去totalweight 变为了-2;
下一轮遍历
server1 cur = cur+weight;// cur = 2,
server2 cur = cur+weight;// cur=0
server3 cur = cur+weight; //cur=2
遍历完就是选中server1,然后server1的cur = cur-totalweight,cur变为-2;
就是这样一遍遍的选择,选择cur最大的,因为cur是根据权重增加的,所以,权重大的被选中的次数更高,实现的很巧妙,也不至于出现不均衡

你可能感兴趣的:(负载均衡,权重,loadbanlance)