一、Ribbon 负载均衡
Ribbon Spring Cloud 体系中的客户端负载均衡器,Ribbon 针对负载均衡提供了多种策略。
相应的类图如下:
部分类描述如下表:
策略类 | 描述 |
---|---|
IRule | 所有策略的最上层接口。规范了负载均衡策略方法实现。 |
AbstractLoadBalancerRule | 所有策略的最上层抽象。提供了 ILoadBalancer 注入。 |
RandomRule | 随机策略。随机选择存活的 server 实例。 |
RoundRobinRule | 轮询策略。按顺序循环轮询存活的 server 实例。 |
RetryRule | 重试策略。装饰者模式委派 RoundRobinRule 获取服务实例,如果实例死亡,在指定时间内,不断通过 RoundRobinRule 尝试获取新的存活的服务实例。 |
BestAvailableRule | 最好可用策略。遍历所有服务实例,找到 server 断路器未打开的服务实例,从其中选出并发链接最低的 server,如果找不到使用 RoundRobinRule 进行娄底。 |
AvailabilityFilteringRule | 可用过滤策略。通过 RoundRobinRule 结合 AbstractServerPredicate 过滤断言进行服务实例过滤,最多过滤10次,如果还是无法获取到服务实例,使用 RoundRobinRule 进行娄底。 |
WeightedResponseTimeRule | 响应时间权重策略。提供有专门的线程去统计服务实例的响应时间,并计算权重,然后根据权重进行服务实例获取,如果无法获取到服务实例,使用RoundRobinRule 进行娄底。 |
ZoneAvoidanceRule | 区域权衡策略。和 AvailabilityFilteringRule 类似,不过其通过 装饰者模式 和 组合模式,通过一系列的复杂断言来过滤服务实例。 |
二、RandomRule
随机策略
类结构
关键代码
public class RandomRule extends AbstractLoadBalancerRule {
public Server choose(ILoadBalancer lb, Object key) {
while (server == null) {
// 获取所有状态为 up 且,可达的服务列表
List<Server> upList = lb.getReachableServers();
// 获取所有服务列表,无论是否可达
List<Server> allList = lb.getAllServers();
// 所有服务实例总数
int serverCount = allList.size();
// 根据服务总数获取随机数
int index = chooseRandomInt(serverCount);
// 从可达的 up 状态的服务实例列表中,根据随机 index 获取服务实例
server = upList.get(index);
// 如果服务存活,返回实例名
if (server.isAlive()) {
return (server);
}
}
}
// 随机数获取
protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);
}
}
三、RetryRule
重试策略
类结构
关键代码
public class RetryRule extends AbstractLoadBalancerRule {
// 娄底策略:轮询策略
IRule subRule = new RoundRobinRule();
// 在指定时间内不断尝试获取服务实例。默认:500 ms
long maxRetryMillis = 500;
public Server choose(ILoadBalancer lb, Object key) {
// 当前请求时间
long requestTime = System.currentTimeMillis();
// 如果第一次获取到,在时间未到达 deadline 时,不断进行重试操作
long deadline = requestTime + maxRetryMillis;
// 通过轮询获取一个服务实例
Server answer = null;
answer = subRule.choose(key);
// 两个条件满足,进入到重试逻辑
// 条件一: 轮询获取到的实例为 null 或者 实例死亡
// 条件二: 时间在允许重试的范围内
if (((answer == null) || (!answer.isAlive())) && (System.currentTimeMillis() < deadline)) {
// 起一个线程,在重试时间到了之后,打断重试的线程
InterruptTask task = new InterruptTask(deadline
- System.currentTimeMillis());
//
while (!Thread.interrupted()) {
answer = subRule.choose(key);
......
if (((answer == null) || (!answer.isAlive())) && (System.currentTimeMillis() < deadline)) {
// 将重试线程重新归入就绪状态,模拟:线程短暂暂停
Thread.yield();
}else{
// 获取到实例,跳出循环
break;
}
}
// 正常获取到实例,手动调用结束定时任务
task.cancel();
}
// 无论是正常结束,还是超时结束,最终都要进行返回
if ((answer == null) || (!answer.isAlive())) {
return null;
} else {
return answer;
}
}
}
四、ZoneAvoidanceRule
区域权衡策略
类结构
类组装图
父类 PredicateBasedRule
关键代码
ZoneAvoidanceRule
父类 PredicateBasedRule
对 choose
方法进行了覆盖,将服务实例的选择,委派给了 AbstractServerPredicate
实现。
public abstract class PredicateBasedRule extends ClientConfigEnabledRoundRobinRule {
// 该方法由其子类实现,如:ZoneAvoidanceRule
public abstract AbstractServerPredicate getPredicate();
@Override
public Server choose(Object key) {
ILoadBalancer lb = getLoadBalancer();
// 服务实例的获取,由 AbstractServerPredicate#chooseRoundRobinAfterFiltering 来完成
Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
if (server.isPresent()) {
return server.get();
} else {
return null;
}
}
}
CompositePredicate
关键代码
类图结构
CompositePredicate#chooseRoundRobinAfterFiltering
服务实例获取时序图
chooseRoundRobinAfterFiltering 方法是在经过断言过滤之后,如果有多个实例,则通过轮询的方式获取实例
首先来看看 ZoneAvoidanceRule
组装的 CompositePredicate
。其由如下两个过滤链组成
AbstractServerPredicate delegate
该过滤链由:
ZoneAvoidancePredicate
+AvailabilityPredicate
组成List<AbstractServerPredicate> fallbacks
该过滤链由:
AvailabilityPredicate
+AbstractServerPredicate.alwaysTrue()
空实现组成
public class ZoneAvoidanceRule extends PredicateBasedRule {
// 组合断言
private CompositePredicate compositePredicate;
public ZoneAvoidanceRule() {
super();
// 组合断言
ZoneAvoidancePredicate zonePredicate = new ZoneAvoidancePredicate(this);
AvailabilityPredicate availabilityPredicate = new AvailabilityPredicate(this);
compositePredicate = createCompositePredicate(zonePredicate, availabilityPredicate);
}
// 组装 CompositePredicate
private CompositePredicate createCompositePredicate(ZoneAvoidancePredicate p1, AvailabilityPredicate p2) {
return CompositePredicate.withPredicates(p1, p2)
.addFallbackPredicate(p2)
.addFallbackPredicate(AbstractServerPredicate.alwaysTrue())
.build();
}
}