Dubbo负载均衡策略之最小活跃策略

Dubbo负载均衡策略之最小活跃策略今天我来学习一下Dubbo负载均衡之一的最小活跃策略-LeastActiveLoadBalance首先,让我们对负载均衡做一个简单的介绍。所谓集负载均衡,其含义就是指将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行。负载均衡、集群容错、服务降级这三个概念在微服务中非常重要。从调用顺序来看,一次完整的RPC调用首先是负载均衡、其次是集群容错、最后是服务降级:负载均衡解决了选哪一个的问题、集群容错解决了换哪一个的问题、而服务降级则是解决了全错了怎么办的问题今天我们要学习的策略是最小活跃策略-Le

大家好,又见面了,我是你们的朋友全栈君。

今天我来学习一下Dubbo负载均衡之一的最小活跃策略-LeastActiveLoadBalance

首先,让我们对负载均衡做一个简单的介绍。所谓集负载均衡,其含义就是指将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行。负载均衡、集群容错、服务降级这三个概念在微服务中非常重要。从调用顺序来看,一次完整的RPC调用首先是负载均衡、其次是集群容错、最后是服务降级:负载均衡解决了选哪一个的问题、集群容错解决了换哪一个的问题、而服务降级则是解决了全错了怎么办的问题

今天我们要学习的策略是最小活跃策略-LeastActiveLoadBalance。顾名思义,这种策略就是寻找调用活跃度最低的服务提供者。

        话不多说,直接分析源码

    protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
        // Number of invokers
        int length = invokers.size();
        // The least active value of all invokers
        int leastActive = -1;
        // The number of invokers having the same least active value (leastActive)
        int leastCount = 0;
        // The index of invokers having the same least active value (leastActive)
        int[] leastIndexes = new int[length];
        // the weight of every invokers
        int[] weights = new int[length];
        // The sum of the warmup weights of all the least active invokers
        int totalWeight = 0;
        // The weight of the first least active invoker
        int firstWeight = 0;
        // Every least active invoker has the same weight value?
        boolean sameWeight = true;


        // Filter out all the least active invokers
        for (int i = 0; i < length; i++) {
            Invoker<T> invoker = invokers.get(i);
            // Get the active number of the invoker
            int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive();
            // Get the weight of the invoker's configuration. The default value is 100.
            int afterWarmup = getWeight(invoker, invocation);
            // save for later use
            weights[i] = afterWarmup;
            // If it is the first invoker or the active number of the invoker is less than the current least active number
            if (leastActive == -1 || active < leastActive) {
                // Reset the active number of the current invoker to the least active number
                leastActive = active;
                // Reset the number of least active invokers
                leastCount = 1;
                // Put the first least active invoker first in leastIndexes
                leastIndexes[0] = i;
                // Reset totalWeight
                totalWeight = afterWarmup;
                // Record the weight the first least active invoker
                firstWeight = afterWarmup;
                // Each invoke has the same weight (only one invoker here)
                sameWeight = true;
                // If current invoker's active value equals with leaseActive, then accumulating.
            } else if (active == leastActive) {
                // Record the index of the least active invoker in leastIndexes order
                leastIndexes[leastCount++] = i;
                // Accumulate the total weight of the least active invoker
                totalWeight += afterWarmup;
                // If every invoker has the same weight?
                if (sameWeight && afterWarmup != firstWeight) {
                    sameWeight = false;
                }
            }
        }
        // Choose an invoker from all the least active invokers
        if (leastCount == 1) {
            // If we got exactly one invoker having the least active value, return this invoker directly.
            return invokers.get(leastIndexes[0]);
        }
        if (!sameWeight && totalWeight > 0) {
            // If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on 
            // totalWeight.
            int offsetWeight = ThreadLocalRandom.current().nextInt(totalWeight);
            // Return a invoker based on the random value.
            for (int i = 0; i < leastCount; i++) {
                int leastIndex = leastIndexes[i];
                offsetWeight -= weights[leastIndex];
                if (offsetWeight < 0) {
                    return invokers.get(leastIndex);
                }
            }
        }
        // If all invokers have the same weight value or totalWeight=0, return evenly.
        return invokers.get(leastIndexes[ThreadLocalRandom.current().nextInt(leastCount)]);
    }

        通过代码我们可以看出, 作者通过

RpcStatus.getStatus(invoker.getUrl(),invocation.getMethodName()).getActive()获取了每个提供者的活跃度,通过 getWeight(invoker, invocation) 获取了每个提供者的权重;最后再返回最低活跃提供者

        如果只有一个最低活跃提供者,直接返回

        if (leastCount == 1) {
            // 如果只存在一个最低活跃的提供者  直接返回
            return invokers.get(leastIndexes[0]);
        }

        如果存在多个、但是不是所有提供者的权重都是一样的:先生成一个随机数(0-最小总权重),循环用这个随机数-最小活跃度提供者们的权重 当减到小于0时 返回此时的最小活跃提供者

        if (!sameWeight && totalWeight > 0) {
            // 生成一个0-最小活跃度提供者总权重之间的整数
            int offsetWeight = ThreadLocalRandom.current().nextInt(totalWeight);
            // 循环用这个随机数-最小活跃度提供者们的权重 当减到小于0时 返回此时的最小活跃提供者
            for (int i = 0; i < leastCount; i++) {
                int leastIndex = leastIndexes[i];
                offsetWeight -= weights[leastIndex];
                if (offsetWeight < 0) {
                    return invokers.get(leastIndex);
                }
            }
        }

        当所有最小活跃提供者权重都一样:随机返回其中一个

invokers.get(leastIndexes[ThreadLocalRandom.current().nextInt(leastCount)]);

        通过上面的代码我们可以看出这个最小活跃的大致逻辑,那么每个提供者的活跃度又是怎么算的呢?

    public static RpcStatus getStatus(URL url, String methodName) {
        String uri = url.toIdentityString();
        ConcurrentMap<String, RpcStatus> map = METHOD_STATISTICS.computeIfAbsent(uri, k -> new ConcurrentHashMap<>());
        return map.computeIfAbsent(methodName, k -> new RpcStatus());
    }

        是通过url和methodName来查出来的活跃度,url我们可以理解为一个提供者的ip,methodName的dubbo接口的方法,可见该活跃度是方法级别的活跃度而非接口级别!此处是取活跃度的地方,那么什么地方又是增加活跃度的呢?请接着往下看

    public static boolean beginCount(URL url, String methodName, int max) {
        max = (max <= 0) ? Integer.MAX_VALUE : max;
        RpcStatus appStatus = getStatus(url);
        RpcStatus methodStatus = getStatus(url, methodName);
        if (methodStatus.active.get() == Integer.MAX_VALUE) {
            return false;
        }
        for (int i; ; ) {
            i = methodStatus.active.get();

            if (i == Integer.MAX_VALUE || i + 1 > max) {
                return false;
            }

            if (methodStatus.active.compareAndSet(i, i + 1)) {
                break;
            }
        }

        appStatus.active.incrementAndGet();

        return true;
    }

        在RpcStatus中有一个beginCount的方法就是用来计数的,而调用这个方法的ActiveLimitFilter的dubbo的filter,这说明每一次发生rpc调用的时都会执行beginCount方法。

        由此,我们可以清晰地看出最小活跃策略就是取目标rpc接口方法调用次数最少的一个提供者来作为本次rpc调用的提供者。但是这种最小活跃只是针对当前消费者,而不能针对整个集群,所以该最小活跃策略仍然不能将资源充分运用起来。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/157494.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 微信公众平台开发接口_小程序注册好了为什么搜索不到

    微信公众平台开发接口_小程序注册好了为什么搜索不到在进行微信公众平台开发之前,需要先接入微信公众平台。具体的步骤在公众平台开发者文档-接入指南已有详细介绍,文档中也提供了验证服务器的PHP示例代码。本文主要提供了Node.js版本的验证代码,同时把步骤细化,让开发者更方便地了解整个接入过程,对初学者更友好。TL;DR在微信公众平台后台的开发者中心/填写服务器配置页面…

    2022年8月21日
    5
  • Python—海龟作图

    Python—海龟作图1、因为海龟作图需要用到”turtle”库,所以先介绍库的三种引用方法:(1):from库名import函数名/*;(2):import库名——>使用时:库名.函数名(3):import库名as函数名2、turtle的使用方法:(1)Turtle库是Python语言中一个很流行的绘制图像的函数库,想象一个小乌龟,在一个横轴为x、纵轴为y的坐标系原点,(0,0)位置开始,它根据一组函数指令的控制,在这个平面坐标系中移动,从而在它爬行的路径上绘制了图形。(2)画布:就是海

    2022年6月28日
    40
  • 互联网架构演变

    互联网架构演变互联网架构演变

    2022年4月22日
    40
  • Redis入门_redis菜鸟教程

    Redis入门_redis菜鸟教程Redis文章目录Redis一、Redis概述二、Redis应用场景三、Redis的下载和安装四、Redis服务的启动五、Redis命令行工具六、Redis基础知识七、Redis数据类型1.key(键)2.String(字符串)3.List(列表)4.Set(集合)5.Zset(有序集合)6.Hash(哈希)八、实践案例九、Redis常用查询指令十、Jedis的使用十一、Redis可视化工具十二、持久化概念十三、RDB十四、AOF十五、AOF重写十六、RDB与AOF的选择一、Re

    2022年9月14日
    2
  • 51单片机 八路抢答器+Proteus仿真[通俗易懂]

    51单片机 八路抢答器+Proteus仿真[通俗易懂]51单片机八路抢答器+Proteus仿真Proteus仿真实例代码1直观,任意看懂#include<reg52.h>unsignedcharcodeled[17]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};//共阳数码管断码//unsignedcharcodeTRY[8]={0xfe,0xfd,0Xfb,0xf7,0xef,0xdf,0

    2022年10月20日
    2
  • 把ocx打包成CAB,并签名

    把ocx打包成CAB,并签名准备好工具包,微软的IESDK里包含这些工具, 但是那个开发包太过庞大,而且操作起来也稍微得繁琐了一些你只需要下载这么几个文件就可以了 文中提到的数字签名工具包,请在此处下载&#

    2022年6月30日
    24

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号