Dubbo笔记-7-负载均衡

负载均衡的封装

容错策略中的负载均衡都使用了抽象父类AbstractCluster中定义的Invoker select方法而并不是直接使用LoadBalance方法,因为抽象父类在LoadBalance的基础上又封装了一些新特性:

  1. 粘滞连接

    粘滞连接用于有状态服务,尽可能让客户端总是向同一提供者发起调用,除非该提供者挂了,再连接另一台.粘滞连接将自动开启延迟连接,以减少长连接数

  2. 可用检测
    Dubbo调用的URL中,如果有含有cluster.availablecheck=false,则不会检测远程调用是否可用,直接调用.如果不设置,则默认会开启检查,对所有的服务都做是否可用的检查,如果不可用,则再次做负载均衡
  3. 避免重复调用
    对于已经调用过的服务,避免重复调用,每次使用同一节点,这种特性主要为了避免并发场景下,某个节点瞬间被大量请求

整个逻辑大致可以分为4步:

  1. 检查URL中是否配置粘滞连接,如果有则使用粘滞连接的Invoker.如果没有配置粘滞连接,或者重复调用检测不通过或可用检测不通过,则进入第2步
  2. 通过ExtensionLoader获取负载均衡的具体实现,并通过负载均衡做节点的选择.对选择出来的节点做重复调用,可用性检测,通过则返回,否则进入第3步
  3. 进行节点的重新选择
    如果需要做可用性检测,则会遍历Directory中得到的所有节点,过滤掉不可用和已经调用过的节点,在剩下的节点中重新做负载均衡;如果不需要做可用性检测,则会遍历Directory中得到的所有节点,但只过滤已经调用过的,在剩余的节点中重新做负载均衡.如果在过滤时将所有节点都过滤了不留节点,则进入第4步
  4. 遍历所有已经调用过的节点,选出可用的节点,再通过负载均衡选出一个节点并返回.如果还找不到可用的节点,则返回null

负载均衡的总体结构

负载均衡算法:

名称 效果
Random 随机,按权重设置随机概率.再一个截面上碰撞的概率高,但调用量越大分布月均匀,且按概率使用权重后也比较均匀,有利于动态调整提供者的权重
RoundRobin 轮询,按公约后的权重设置轮询比例.存在 慢的提供者积累请求 的问题
LeastActive 最少活跃调用数.如果活跃数相同则随机调用.使慢的提供者收到更少请求
ConsistentHash 一致性Hash,相同参数的请求总是发到同一提供者.当提供者挂掉时,原本发往该提供者的请求,基于虚拟节点,会平摊到其他提供者,不会引起剧烈变动

4中负载均衡算法都继承自同一个抽象类,使用的也是模板模式,抽象父类中已经把通用的逻辑完成,留一个抽象的doSelect方法给子类实现

Random负载均衡

Random负载均衡

RoundRobin负载均衡

普通的轮询的好处是每个节点获得的请求是很均匀的,如果某些节点的负载能力比较弱,则这个节点会堆积较多的请求.
普通轮询之外是权重轮询.权重轮询又分为普通权重轮询和平滑权重轮询.普通权重轮询会造成某个节点会突然频繁选中,这样很容易突然让一个节点流量暴增.平滑权重轮询在轮询时会穿插其他节点,让整个服务器的选择的过程比较均匀,不会逮住一个节点一直调用.Dubbo使用平滑权重轮询.

TODO:平滑权重轮询实现细节

LeastActive负载均衡

最少活跃调用数负载均衡.框架会记下每个Invoker的活跃数,每次只从活跃数最少的Invoker里选一个节点.这个算法需要配合ActiveLimitFilter过滤器来计算每个接口方法的活跃数.最少活跃负载均衡可以看做Random负载均衡的加强版,因为最后根据权重做负载均衡的时候,使用的算法和Random是一样的

其会遍历所有Invoker,不断寻找最小的活跃数,如果有多个Invoker活跃数都等于leastActive,则把他们保存到同一个集合中,最后在这个Invoker集合中再通过随机的方式选出一个Invoker

一致性Hash负载均衡

一致性Hash负载均衡可以让参数相同的请求每次都路由到相同的机器上.相比于直接使用Hash负载均衡而言,某些节点下线时,请求会平摊到其他服务提供者,不会引起剧烈变动

Merger的实现

当一个接口有多种实现,消费者有需要同时引用不同的实现时,可以用group来区分不同的实现.如:

1
2
<dubbo:service group="group1" interface="com.xxx.SomeInterface" />
<dubbo:service group="group2" interface="com.xxx.SomeInterface" />

TODO: Merger和Mock