一、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 mslong 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 {// 该方法由其子类实现,如:ZoneAvoidanceRulepublic abstract AbstractServerPredicate getPredicate();@Overridepublic 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);}// 组装 CompositePredicateprivate CompositePredicate createCompositePredicate(ZoneAvoidancePredicate p1, AvailabilityPredicate p2) {return CompositePredicate.withPredicates(p1, p2).addFallbackPredicate(p2).addFallbackPredicate(AbstractServerPredicate.alwaysTrue()).build();}}
过滤执行操作

