IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> dubbo 负载均衡值最下活跃度的实现原理 -> 正文阅读

[Java知识库]dubbo 负载均衡值最下活跃度的实现原理

1.概括

dubbo 2.7 中提供了4中负载均衡算法,分别为:随机、轮询、一致性哈希、最小活跃度,分别对应于源码文件的 RandomLoadBalance.class、RoundRobinLoadBalance.class、ConsistentHashLoadBalance、LeastActiveLoadBalance.class。

2.使用

对于dubbo中负载均衡的配置使用也是很简单,只需要在对应的服务提供方或消费端配置即可,两边都配置优先取消费端,配置方式如下

服务提供端

/**
 * 负载均衡
 * roundrobin/random/leastactive/consistenthash
 * 轮询/加权随机(默认)/最少活跃度/一致性hash
 */
@Service(loadbalance = "roundrobin")   // 这里的 @Service是dubbo的注解,不是Spring的注解
public class PayServiceImpl implements IPayService {
    @Override
    public String pay(String id) {
        System.out.println("request coming");
        return "dubbo-springboot: pay————>" + id;
    }
}

服务消费端

/**
 * 服务调用
 */
@RestController
@RequestMapping("/pay")
public class PayController {

    // roundrobin/random/leastactive/consistenthash
    @Reference(loadbalance = "roundrobin")
    private IPayService payService;

    @GetMapping("/{id}")
    public String pay(@PathVariable String id) {
        return payService.pay(id);
    }

}

这样就可以了

3.源码分析

这里仅分析最小活跃度的源码实现,其他的负载均衡相对简单。

如果要使用最小活跃度的负载均衡算法,可以配置最小活跃度对应的过滤器来使用,如下

@Reference(loadbalance = "leastactive", filter = "actives") 
private IPayService payService;

?首先配置了 actives 过滤器,服务会使得 ActiveLimitFilter.class 这个过滤器生效,这个过滤器会在invoker被调用的时候进行活跃度的维护(invoker是dubbo中对于处理的封装,包括连接和调用处理,只要拿到invoker调用就可以完成远程通信)。

接下来是重点部分?LeastActiveLoadBalance.class 的 doSelect方法,源码如下:

    protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
        // Number of invokers   invoker 数量
        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 invokes
        int totalWeight = 0;
        // The weight of the first least active invoke
        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 invoke   获得活跃度,通过 uti 和 方法名
            int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive();
            // Get the weight of the invoke configuration. The default value is 100.   获得权重,没设置默认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) {
                // 第一次一定能走这里,后边当拿到的invoker的活跃度小于最小活跃度,则进来这里的逻辑
                // Reset the active number of the current invoker to the least active number        记录获得的最小活跃度
                leastActive = active;   
                // Reset the number of least active invokers      拥有最小活跃度的invoker数量
                leastCount = 1;
                // Put the first least active invoker first in leastIndexes   记录拥有最小活跃度的invoker的下标到leastIndexes[0]
                leastIndexes[0] = i;
                // Reset totalWeight     总权重
                totalWeight = afterWarmup;
                // Record the weight the first least active invoker   记录最小活跃的的invoker的权重
                firstWeight = afterWarmup;    因为最小活跃度的invoker只有1个,所以是等权的
                // Each invoke has the same weight (only one invoker here)
                sameWeight = true;

                // If current invoker's active value equals with leaseActive, then accumulating.
                // 如果当前遍历的invoker的活跃度和当前记录的最小活跃度相等,走这里
            } else if (active == leastActive) {
                // leastCount自增,并且记录最小活跃度的invoker的下标到leastIndexes数组
                // 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;
                // 如果之前是等权,并且现在获得的最小活跃度的invoker的权重和之前最小活跃度的invoker的权重不一样,则不再等权
                // If every invoker has the same weight?
                if (sameWeight && i > 0
                        && afterWarmup != firstWeight) {
                    sameWeight = false;
                }
            }
        }

        // 只有一个最小活跃度的invoker,则就选择这个
        // 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]);
        }

        // 如果不等权,并且总权重 > 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.
            // 对拥有最小活跃的的invoker进行加权随机
            for (int i = 0; i < leastCount; i++) {
                int leastIndex = leastIndexes[i];
                offsetWeight -= weights[leastIndex];
                if (offsetWeight < 0) {
                    return invokers.get(leastIndex);
                }
            }
        }

        // 等权的情况则在最小活跃度的invoker中随机获取
        // If all invokers have the same weight value or totalWeight=0, return evenly.
        return invokers.get(leastIndexes[ThreadLocalRandom.current().nextInt(leastCount)]);
    }

梳理下就是:

1.拿到当前的所有 invoker(因为是集群,会有多个)

2.遍历所有invoker,拿到其中?active(活跃度在每次调用会被ActiveLimitFilter维护)最小的一个或多个invoker,并且记录并统计拥有最小活跃度的invoker的权重,不设置默认为200

3.最后如果拥有最小活跃度的invoker只有1个,则就返回这个;如果大于1个,且他们的权重不是都一样的,则加权随机(随机获得在总权重之内的非负整数,落到谁的权重范围内则就是谁);如果是等权,则直接等权随机(在拥有最小活跃度的invoker中随机获得一个)。

具体的流程看上边源码注释即可

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-09 10:06:43  更:2021-08-09 10:07:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/10 16:56:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码