负载均衡策略
AbstractLoadBalancerRule
负载均衡策略的抽象类,在该类中定义了负载均衡器ILoadBalancer对象,该对象能够在具体实现选择服务策略时,获取到
一些负载均衡中维护的信息来作为分配依据,并以此设计一些算法来实现针对特定场景的高效策略
RandomRule
随机选择一个服务实例
RoundRobinRule
线性轮询的方式
RetryRule
实现了一个具备重试机制的实例选择功能
WeightedResponseTimeRule
该策略是对RoundRobinRule的扩展,增加了根据实例的运行情况来计算权重,并根据权重来挑选实例,以达到更优的分配效果
定时任务
serverWeightTimer.schedule(new DynamicServerWeightTask(), 0, serverWeightTaskTimerInterval);启动一个定时任务,
用来为每个服务实例计算权重
该方法的实现主要分为两个步骤:
根据LoadBalancerStats中记录的每个实例的统计信息,累加所有实例的平均响应时间,得到平均响应时间总和
totalResponseTime,该值会用于后续的计算。
为负载均衡器中维护的实例清单逐个计算权重(从第一个开始),计算规则为weightSoFar+totalResponseTime
- 实例的平均响应时间,其中weightSoFar初始为零,并且每计算好一个权重需要累加到weightSoFar上供下一次计算使用
实例选择
WeightedResponseTimeRule选择实例的实现与之前介绍的算法类似,下面是它主体的算法
主要分两步:
生成一个[0, 最大权重值]区间内的随机数。
遍历权重列表,比较权重值与随机数的大小,如果权重值大于等于随机数,就拿当前权重列表的索引值
去服务实例列表中获取具体的实例。而权重区间边界的开闭原则根据算法,正常每个区间为(x, y]的形式,
但是第一个实例和最后一个实例为什么不同,由于随机数的最小取值可以为0,所以第一个实例的下限是
闭合区,同时随机数的最大值取不到最大权重值,所以最后一个实例的上限是开区间
若继续以上面的数据为例进行服务实例的选择,则该方法会从[0, 690)区间中选出一个随机数,比如选出的
随机数为230,由于位于第二个区间,所以此时就会选择实例B来进行请求
ClientConfigEnableRoundRobinRule
该策略较为特殊,一般不直接使用它,因为本身没有特殊的处理逻辑,内部定义了一个RoundRobinRule,
choose()方法默认使用RoundRobinRule的线性轮循机制,
通过继承该策略,在子类中做一些高级策略时通常有可能会存在一些无法实施的情况,那么就可以用父类的实现
作为备选。
BestAvailableRule
ClientConfigEnableRoundRobinRule的子类,主要是找出并发请求数最小的一个
PredicateBasedRule
这是一个抽象策略,它也继承了ClientConfigEnabledRoundRobinRule,从其命名中可以看出这是一个
基于Predicate实现的策略,Predicate是Google Guava Collection工具对集合进行过滤的条件接口
如下所示,它定义了一个抽象方法getPredicate()来获取AbstractServerPredicate对象的实现,而在choose()
方法中,通过AbstractServerPredicate的chooseRoundRobinAfterFiltering()方法来选出具体的服务实例
在 AbstractServerPredicate中
先通过内部定义的getEligibleServers()方法来获取备选的实例清单(过滤),如果为空,用Optional.abstent()表示
不存在,否则线性轮循
如下 是getEligibleServers()方法
使用this.apply()方法来判断是否需要保留,在子类中查apply()方法的实现
AvailabilityFilteringRule
该策略继承上面的抽象策略PredicateBaseRule,所以它也继承了“先过滤,再轮循”的基本逻辑,
其中过滤条件使用类AvailabilityPredicate
AvailabilityFilterRule的choose()方法也不同
可以看到,它并没有像父类那样,先遍历所有的节点进行过滤,然后在过滤后的集合中选择实例。而是
先以线性的方式选择一个实例,接着用过滤条件来判断该实例是否满足要求,不满足再选择下一个实例,
优化类父类每次都要遍历所有实例的开销
ZoneAvoidanceRule
它使用了CompositePredicate来进行服务实例清单的过滤。这是一个组合过滤条件,构造方法中,以
ZoneAvoidancePredicate为主过滤条件,AvailabilityPredicate为次过滤条件
ZoneAvoidanceRule并没有重写choose()方法,所以遵循父类“先过滤,在轮循”,
过滤条件是CompositePredicate,源码如下
可以看到定义了一个主过滤条件AbstractServerPredicate delegate以及一组次过滤条件列表List fallbacks,
所以它的次过滤列表是可以多个的,