ITPub博客

首页 > 数据库 > 数据库开发技术 > Dubbo服务负载均衡原理

Dubbo服务负载均衡原理

原创 数据库开发技术 作者:服务端技术栈 时间:2022-04-01 20:54:56 0 删除 编辑


负载均衡是rpc框架必须具备的一个能力,在Dubbo中负载均衡是在服务消费者这边实现的,也叫做客户端负载均衡。


为什么需要负载均衡机制呢?

当服务提供者集群部署的时候,服务消费方每次调用都必须选择其中一台服务提供者进行远程rpc调用。本文将分析Dubbo的负载均衡算法。


Dubbo 支持哪些负载均衡算法

1、加权随机(默认)

2、加权轮训

问题:

存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。

3、一致性hash

特点:相同参数的请求总是发到同一提供者。当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。

4、加权最少活跃数

最少活跃数优先,相同活跃数的随机,活跃数指调用前后计数差(调用的慢,调用时间越长,计数差越大,因此调用的越快,活跃数越少)。使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。 


源码分析

1、随机负载均衡策略

public class RandomLoadBalance extends AbstractLoadBalance {
public static final String NAME = "random";
/** * Select one invoker between a list using a random criteria * @param invokers List of possible invokers * @param url URL * @param invocation Invocation * @param <T> * @return The selected invoker */ @Override protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) { // Number of invokers int length = invokers.size(); // Every invoker has the same weight? boolean sameWeight = true; // the weight of every invokers int[] weights = new int[length]; // the first invoker's weight int firstWeight = getWeight(invokers.get(0), invocation); weights[0] = firstWeight; // The sum of weights int totalWeight = firstWeight;        //计算每个服务提供者的权重 for (int i = 1; i < length; i++) { int weight = getWeight(invokers.get(i), invocation); // save for later use weights[i] = weight; // Sum totalWeight += weight; if (sameWeight && weight != firstWeight) { sameWeight = false; } } //通过线程安全的随机生成器生成随机 if (totalWeight > 0 && !sameWeight) {            // 根据总权重计算一个随机权重偏移量 int offset = ThreadLocalRandom.current().nextInt(totalWeight); // Return a invoker based on the random value. for (int i = 0; i < length; i++) { //遍历每个权重值,得到随机偏移量对应的权重 offset -= weights[i]; if (offset < 0) { return invokers.get(i); } } } // If all invokers have the same weight value or totalWeight=0, return evenly. return invokers.get(ThreadLocalRandom.current().nextInt(length));    }}

总结:

加权随机是在随机的基础上,给每个服务提供者加上一个权重值。


2、加权最少活跃数

public class LeastActiveLoadBalance extends AbstractLoadBalance {
public static final String NAME = "leastactive"; @Override 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 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 int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive(); // Get the weight of the invoke 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 是找到活跃数最小的一个invoker 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 //只要找到了更小活跃数的 invoker 就重置计数 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) { //这里是为了 找出并记录和最小活跃数相同的invoker // Record the index of the least active invoker in leastIndexes order leastIndexes[leastCount++] = i; // Accumulate the total weight of the least active invoker //累计 相同活跃数invoker的 权重 totalWeight += afterWarmup; // If every invoker has the same weight? if (sameWeight && i > 0 && 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)]); }}

总结:

先过滤出调用次数最少(最不活跃)的调用者数量,并计算这些调用者的权重和数量。如果只有一个调用程序,则直接使用该调用程序;如果有多个调用者并且权重不相同,则根据总权重随机;如果有多个调用者且权重相同,则将其随机调用。 


负载均衡机制是分布式系统中必须掌握的一项技术,通过分析Dubbo的源码实现,我们知道了常用的负载均衡算法以及一些优化版本,为学习其他中间件负载均衡机制打下基础。

原文作者:服务端技术栈;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2019-03-08

  • 博文量
    97
  • 访问量
    41425