Dubbo LoadBalance基于权重的随机负载均衡算法提高服务性能

 更新时间:2023年10月17日 08:40:38   作者:jacheut  
这篇文章主要为大家介绍了Dubbo LoadBalance基于权重的随机负载均衡算法提高服务性能详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪<BR>

导读

Dubbo是一个分布式服务框架,能避免单点故障和支持服务的横向扩容。一个服务通常会部署多个实例。如何从多个服务 Provider 组成的集群中挑选出一个进行调用,就涉及到一个负载均衡的策略。

负载均衡职责是将网络请求或者其他形式的负载“均摊”到不同的服务节点上,从而避免服务集群中部分节点压力过大、资源紧张,而另一部分节点比较空闲的情况。通过合理的负载均衡算法,我们希望可以让每个服务节点获取到适合自己处理能力的负载,实现处理能力和流量的合理分配。常用的负载均衡可分为软件负载均衡(比如,日常工作中使用的 Nginx)和硬件负载均衡(主要有 F5、Array、NetScaler 等,不过开发工程师在实践中很少直接接触到)。

Dubbo提供了 5 种负载均衡实现

  • 基于 Hash 一致性的 ConsistentHashLoadBalance;
  • 基于权重随机算法的 RandomLoadBalance;
  • 基于最少活跃调用数算法的 LeastActiveLoadBalance;
  • 基于加权轮询算法的 RoundRobinLoadBalance;
  • 基于最短响应时间的 ShortestResponseLoadBalance 。

LoadBalance 是一个扩展接口,默认使用的扩展实现是 RandomLoadBalance,其定义如下所示,其中的 @Adaptive 注解参数为 loadbalance,即动态生成的适配器会按照 URL 中的 loadbalance 参数值选择扩展实现类。

@SPI(RandomLoadBalance.NAME)
public interface LoadBalance {
    @Adaptive("loadbalance")
    <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
}

LoadBalance 接口中 select() 方法的核心功能是根据传入的 URL 和 Invocation,以及自身的负载均衡算法,从 Invoker 集合中选择一个 Invoker 返回。

ConsistentHashLoadBalance(一致性 Hash算法)

底层使用一致性 Hash 算法实现负载均衡。

一致性 Hash 负载均衡可以让参数相同的请求每次都路由到相同的服务节点上,这种负载均衡策略可以在某些 Provider 节点下线的时候,让这些节点上的流量平摊到其他 Provider 上,不会引起流量的剧烈波动。

假设现在有 1、2、3 三个 Provider 节点对外提供服务,有 100 个请求同时到达,如果想让请求尽可能均匀地分布到这三个 Provider 节点上,我们可能想到的最简单的方法就是 Hash 取模,即 hash(请求参数) % 3。如果参与 Hash 计算的是请求的全部参数,那么参数相同的请求将会落到同一个 Provider 节点上。不过此时如果突然有一个 Provider 节点出现宕机的情况,那我们就需要对 2 取模,即请求会重新分配到相应的 Provider 之上。在极端情况下,甚至会出现所有请求的处理节点都发生了变化,这就会造成比较大的波动。

为了避免因一个 Provider 节点宕机,而导致大量请求的处理节点发生变化的情况,我们可以考虑使用一致性 Hash 算法。一致性 Hash 算法的原理也是取模算法,与 Hash 取模的不同之处在于:Hash 取模是对 Provider 节点数量取模,而一致性 Hash 算法是对 2^32 取模。

一致性 Hash 算法需要同时对 Provider 地址以及请求参数进行取模:

hash(Provider地址) % 2^32

hash(请求参数) % 2^32

Provider 地址和请求经过对 2^32 取模得到的结果值,都会落到一个 Hash 环上.

一致性 Hash节点均匀分布

我们按顺时针的方向,依次将请求分发到对应的 Provider。这样,当某台 Provider 节点宕机或增加新的 Provider 节点时,只会影响这个 Provider 节点对应的请求。

在理想情况下,一致性 Hash 算法会将这三个 Provider 节点均匀地分布到 Hash 环上,请求也可以均匀地分发给这三个 Provider 节点。但在实际情况中,这三个 Provider 节点地址取模之后的值,可能差距不大,这样会导致大量的请求落到一个 Provider 节点上。就出现了数据倾斜的问题。所谓数据倾斜是指由于节点不够分散,导致大量请求落到了同一个节点上,而其他节点只会接收到少量请求的情况。

为了解决一致性 Hash 算法中出现的数据倾斜问题,又演化出了 Hash 槽的概念。

Hash 槽解决数据倾斜的思路是:既然问题是由 Provider 节点在 Hash 环上分布不均匀造成的,那么可以虚拟出 n 组 P1、P2、P3 的 Provider 节点 ,让多组 Provider 节点相对均匀地分布在 Hash 环上。如下图所示,相同阴影的节点均为同一个 Provider 节点,比如 P1-1、P1-2……P1-99 表示的都是 P1 这个 Provider 节点。引入 Provider 虚拟节点之后,让 Provider 在圆环上分散开来,以避免数据倾斜问题。

RandomLoadBalance(加权随机算法)

RandomLoadBalance 是一个简单、高效的负载均衡实现,它也是 Dubbo 默认使用的 LoadBalance 实现。

下面我们通过随机数生成器在 [0, 10) 这个范围内生成一个随机数,然后计算这个随机数会落到哪个区间中。例如,随机生成 4,就会落到 Provider A 对应的区间中,此时 RandomLoadBalance 就会返回 Provider A 这个节点。

接下来我们再来看 RandomLoadBalance 中 doSelect() 方法的实现,其核心逻辑为三个关键点:

  • 计算每个 Invoker 对应的权重值以及总权重值;
  • 当各个 Invoker 权重值不相等时,计算随机数应该落在哪个 Invoker 区间中,返回对应的 Invoker 对象;
  • 当各个 Invoker 权重值相同时,随机返回一个 Invoker 即可。

RandomLoadBalance 经过多次请求后,能够将调用请求按照权重值均匀地分配到各个 Provider 节点上。

LeastActiveLoadBalance(最小活跃数负载均衡算法)

LeastActiveLoadBalance 使用的是最小活跃数负载均衡算法。它认为当前活跃请求数越小的 Provider 节点,剩余的处理能力越多,处理请求的效率也就越高,那么该 Provider 在单位时间内就可以处理更多的请求,所以我们应该优先将请求分配给该 Provider 节点。

LeastActiveLoadBalance 需要配合 ActiveLimitFilter 使用,ActiveLimitFilter 会记录每个接口方法的活跃请求数,在 LeastActiveLoadBalance 进行负载均衡时,只会从活跃请求数最少的 Invoker 集合里挑选 Invoker。

在 LeastActiveLoadBalance 的实现中,首先会选出所有活跃请求数最小的 Invoker 对象,之后的逻辑与RandomLoadBalance 完全一样,按照这些 Invoker 对象的权重挑选最终的Invoker 对象。

RoundRobinLoadBalance(加权轮询负载均衡算法)

轮询指的是将请求轮流分配给每个 Provider。例如,有 A、B、C 三个 Provider 节点,按照普通轮询的方式,我们会将第一个请求分配给 Provider A,将第二个请求分配给 Provider B,第三个请求分配给 Provider C,第四个请求再次分配给 Provider A……如此循环往复。

轮询是一种无状态负载均衡算法,实现简单,适用于集群中所有 Provider 节点性能相近的场景。 但现实情况中就很难保证这一点了,因为很容易出现集群中性能最好和最差的 Provider 节点处理同样流量的情况,这就可能导致性能差的 Provider 节点各方面资源非常紧张,甚至无法及时响应了,但是性能好的 Provider 节点的各方面资源使用还较为空闲。这时我们可以通过加权轮询的方式,降低分配到性能较差的 Provider 节点的流量。

加权之后,分配给每个 Provider 节点的流量比会接近或等于它们的权重比。例如,Provider 节点 A、B、C 权重比为 5:1:1,那么在 7 次请求中,节点 A 将收到 5 次请求,节点 B 会收到 1 次请求,节点 C 则会收到 1 次请求。

ShortestResponseLoadBalance(最短响应时间的负载均衡算法)

ShortestResponseLoadBalance 是Dubbo 2.7 版本之后新增加的一个 LoadBalance 实现类。它实现了最短响应时间的负载均衡算法,也就是从多个 Provider 节点中选出调用成功的且响应时间最短的 Provider 节点,不过满足该条件的 Provider 节点可能有多个,所以还要再使用随机算法进行一次选择,得到最终要调用的 Provider 节点。

以上就是Dubbo的负载均衡(LoadBalance)原理的详细内容,更多关于Dubbo 负载均衡的资料请关注脚本之家其它相关文章!

相关文章

  • Java设计模式之观察者模式observer pattern详解

    Java设计模式之观察者模式observer pattern详解

    这篇文章主要介绍了Java设计模式之观察者模式observer pattern详解,当一个对象发生数据变化时,通知其他相关的一系列对象,接受到通知的对象根据该对象的变化进行相应处理以响应变化的过程,需要的朋友可以参考下
    2023-12-12
  • spring mvc 和ajax异步交互完整实例代码

    spring mvc 和ajax异步交互完整实例代码

    本篇文章主要介绍了spring mvc 和ajax异步交互完整实例代码,简单的AJAX+SpringMVC的异步交互小例子,有兴趣的可以了解一下。
    2017-02-02
  • Spring Security实现两周内自动登录

    Spring Security实现两周内自动登录"记住我"功能

    登录过程中经常使用的“记住我”功能,也就是我们经常会在各种网站登陆时见到的"两周内免登录",“三天内免登录”的功能。今天小编给大家分享基于Spring Security实现两周内自动登录"记住我"功能,感兴趣的朋友一起看看吧
    2019-11-11
  • java实现上传图片尺寸修改和质量压缩

    java实现上传图片尺寸修改和质量压缩

    这篇文章主要为大家详细介绍了java实现上传图片尺寸修改和质量压缩,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • Java EE项目中的异常处理总结(一篇不得不看的文章)

    Java EE项目中的异常处理总结(一篇不得不看的文章)

    什么是异常?运行时发生的可被捕获和处理的错误。这篇文章主要介绍了Java EE项目中的异常处理总结,有需要的可以了解一下。
    2016-11-11
  • Java如何在PPT中绘制图形

    Java如何在PPT中绘制图形

    这篇文章主要介绍了Java如何在PPT中绘制图形,Microsoft PowerPoint可支持在幻灯片中插入各种类型的图形并且可设置图形填充、线条颜色、图形大小、位置等。下面将通过Java编程来演示在PPT中绘制图形的方法,需要的朋友可以参考下
    2019-07-07
  • java开发MyBatis中常用plus实体类注解符详解

    java开发MyBatis中常用plus实体类注解符详解

    这篇文章主要为大家介绍了java开发MyBatis常用的plus实体类注解符示例应用详解有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2021-10-10
  • 详解java中this.getClass()和super.getClass()的实例

    详解java中this.getClass()和super.getClass()的实例

    这篇文章主要介绍了详解java中this.getClass()和super.getClass()的实例的相关资料,需要的朋友可以参考下
    2017-08-08
  • 五种Java多线程同步的方法

    五种Java多线程同步的方法

    这篇文章主要为大家详细介绍了五种Java多线程同步的方法,需要的朋友可以参考下
    2015-09-09
  • 详解SpringBoot如何让指定的Bean先加载

    详解SpringBoot如何让指定的Bean先加载

    这篇文章主要给大家介绍了在 SpringBoot 中如何让自己的某个指定的 Bean 在其他 Bean 前完成被 Spring 加载,文中通过代码示例给大家讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-06-06

最新评论