本文已参与「新人创作礼」活动,一起开启掘金创作之路。
SpringCloud整合Ribbon - 默认负载均衡算法选择Server
ZoneAwareLoadBalancer impl DynamicServerListLoadBalancer impl BaseLoadBalancer
通过LoadBalancer从一个服务对应的server list中选择一个server出来,保持负载均衡,将请求均匀的发送各个服务器上去
LoadBalancer.chooseServer()方法,通过内置的负载均衡算法,选择一个server
ZoneAwareLoadBalancer,机房概念,多机房的话,可以感知到多机房的,将一个机房里的请求,转发至同机房里部署的其他的服务实例。内部每个zone,每个机房对应一个LoadBalancer。
ZoneAwareLoadBalancer内部基于BaseLoadBalander工作,封装多个机房,对每个机房的请求,找每个机房对应的BaseLoadBalancer,调用BaseLoadBalancer.chooseServer()方法选择了一个server。
BaseLoadBalancer.chooseServer()方法内部通过策略模式调用对应的IRule封装的负载均衡算法,选择一台服务器。
策略模式:封装算法
IRule代表封装的负载均衡的算法
- 上下文角色(Context):用来操作策略的上下文环境,屏蔽客户端对策略直接访问;
- 抽象策略角色(Strategy):规定策略的行为;
- 具体策略角色(ConcreteStrategy):具体的策略实现;
ZoneAvoidanceRule -> PredicateBasedRule -> ClientConfigEnabledRoundRobinRule -> IRule
IRule用的是RibbonClientConfiguraiton中实例化的ZoneAvoidanceRule。
package com.netflix.loadbalancer;
public interface IRule{
public Server choose(Object key);
public void setLoadBalancer(ILoadBalancer lb);
public ILoadBalancer getLoadBalancer();
}
ZoneAvoidanceRule提供CompositePredicate,调用父类PredicateBasedRule.choose()方法,通过CompositePredicate执行过滤规则,过滤掉一批server,然后用round robin轮询算法,依次获取下一个server
// PredicateBasedRule.java
@Override
public Server choose(Object key) {
ILoadBalancer lb = getLoadBalancer();
Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
if (server.isPresent()) {
return server.get();
} else {
return null;
}
}
服务实例列表(server list)
192.168.1.2:7071
192.168.1.2:7070
CompositePredicate:从服务实例列表中,第一台开始,每台机器访问一次,依次循环往复
CompositePredicate -> AbstractServerPredicate -> Predicate
// ((CompositePredicate)AbstractServerPredicate).chooseRoundRobinAfterFiltering
public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {
List<Server> eligible = getEligibleServers(servers, loadBalancerKey);
if (eligible.size() == 0) {
return Optional.absent();
}
return Optional.of(eligible.get(incrementAndGetModulo(eligible.size())));
}
// ((CompositePredicate)AbstractServerPredicate).incrementAndGetModulo
// round robin轮询算法
private int incrementAndGetModulo(int modulo) {
for (;;) {
int current = nextIndex.get();
int next = (current + 1) % modulo;
if (nextIndex.compareAndSet(current, next) && current < modulo)
return current;
}
}
modulo:2,代表的是当前服务实例数量。
AbstractServerPredicate.incrementAndGetModulo()方法,采用round robin轮询算法,依次遍历选择server list中的每一台server