# ribbon-spring-boot-starter ## ribbon客户端负载均衡 > ribbon客户端负载均衡: 消费方从注册中心上获取接口调用地址列表,客户端实现负载均衡算法(轮询,随机,hash一致性,权重)等原理获取接口地址列表,采用算法规则获取选择一个接口地址,并发起远程调用 ## 负载均衡主要组件 ![](https://img.kancloud.cn/3e/69/3e692edf8c833765456dd723a8a746f2_1133x559.png) | 组件 | 作用 | | --- | --- | | ILoadBalancer | 定义一系列的操作接口,比如选择服务实例 | | IRule| 算法策略,内置算法策略来为服务实例的选择提供服务| | ServerList| 负责服务实例信息的获取,可以获取配置文件中的,也可以从注册中心获取| | ServerListFilter| 过滤掉某些不想要的服务实例信息| | ServerListUpdater| 更新本地缓存的服务实例信息| | IPing| 对已有的服务实例进行可用性检查,保证选择的服务都是可用的| ## 规则接口 ![](https://img.kancloud.cn/22/5e/225ee4d612a1d96a86924a562d73a802_723x279.png) ![](https://img.kancloud.cn/36/a8/36a8db4ef04f1c9e2d88544ea27c5d5e_516x236.png) ## 默认规则 ![](https://img.kancloud.cn/cb/df/cbdff2c642ef0495dfe668fdf3613366_848x213.png) ![](https://img.kancloud.cn/fd/c0/fdc06f836e0b4485eff1937bc8cc835b_1227x526.png) ## 自定义规则 ![](https://img.kancloud.cn/41/a2/41a29005c1f2badbef1c78c21eb98d25_1631x858.png) ## 替换自定义规则 ![](https://img.kancloud.cn/2d/93/2d93a3951ec076bb1672c8ddd2bd3461_1621x664.png) ![](https://img.kancloud.cn/b3/cf/b3cf8400b1c9f9086b191f11afad7da3_1433x674.png) ![](https://img.kancloud.cn/63/72/637203b7f244dabde6b335017557d4f2_430x156.png) ## 自定义过滤规则 ![](https://img.kancloud.cn/1a/a2/1aa22d466f41a82206a635382e7ede6d_957x350.png) ### 默认规则返回false时 ![](https://img.kancloud.cn/4d/82/4d8281f0269b216b3582c918a11ec471_1388x515.png) ![](https://img.kancloud.cn/a7/93/a793dd57ed7fe5da85fed8ba81a6dfde_1416x734.png) ![](https://img.kancloud.cn/ed/9f/ed9f52df172de2ef5fc4a7697873355a_1436x578.png) #### 在上面`choose`函数中调用的`chooseRoundRobinAfterFiltering`方法先通过内部定义的`getEligibleServers`函数来获取备选的实例清单(实现了过滤),由于MetadataAwarePredicate返回了false,返回的清单为空,则用`Optional.absent()`来表示不存在 ![](https://img.kancloud.cn/3d/5c/3d5cd950a4951b27ab345ebdffb42b81_1579x668.png) ![](https://img.kancloud.cn/9f/e3/9fe332e40817757762d2fd36151bf642_1708x637.png) ### 默认规则返回true时 ![](https://img.kancloud.cn/a6/1f/a61f02db23cbfd68ae2a648df812a215_1228x666.png) #### 在上面`choose`函数中调用的`chooseRoundRobinAfterFiltering`方法先通过内部定义的`getEligibleServers`函数来获取备选的实例清单(实现了过滤),由于MetadataAwarePredicate返回了true ,以线性轮询的方式从备选清单中获取一个实例。 ``` // 线性轮询 private int incrementAndGetModulo(int modulo) { for (;;) { int current = nextIndex.get(); int next = (current + 1) % modulo; if (nextIndex.compareAndSet(current, next)) return current; } } ``` ## 总结: 在了解了整体逻辑之后,我们来详细看看实现过滤功能的`getEligibleServers`函数。从源码上看,它的实现结构非常简单清晰,通过遍历服务清单,使用`this.apply`方法来判断实例是否需要保留,是就添加到结果列表中。 ## Predicate 介绍 ### Predicate 流程处理 #### `chooseRoundRobinAfterFiltering` 内部的细节 ``` @Override public Server choose(Object key) { ILoadBalancer lb = getLoadBalancer(); // 过滤之后循环选择server Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key); if (server.isPresent()) { return server.get(); } else { return null; } } ``` ![](https://img.kancloud.cn/11/1f/111f36fabf0aa23551593273cc073632_1231x652.png) #### `getEligibleServers`函数来获取备选的实例清单 ``` @Override public List<Server> getEligibleServers(List<Server> servers, Object loadBalancerKey) { // 先调用抽象类过滤 List<Server> result = super.getEligibleServers(servers, loadBalancerKey); // 再进行过滤 Iterator<AbstractServerPredicate> i = fallbacks.iterator(); while (!(result.size() >= minimalFilteredServers && result.size() > (int) (servers.size() * minimalFilteredPercentage)) && i.hasNext()) { AbstractServerPredicate predicate = i.next(); result = predicate.getEligibleServers(servers, loadBalancerKey); } return result; } ``` ![](https://img.kancloud.cn/76/e2/76e2a01e222e545417467ed8c8ea6c7c_1286x353.png) #### 通过遍历服务清单 ![](https://img.kancloud.cn/30/a8/30a84f1eb74133c79c4b39f2b623099b_1224x658.png) ![](https://img.kancloud.cn/38/c7/38c77110da6a42eab97dbcfd25e200d7_1223x637.png) #### 使用`this.apply`方法来判断实例是否需要保留,是就添加到结果列表中 ![](https://img.kancloud.cn/63/ac/63acca6657420bc49bb3b36a53036a0f_1229x658.png) ![](https://img.kancloud.cn/d0/93/d09346ceefc015cf8e43820780e91c9f_1216x656.png) ![](https://img.kancloud.cn/0b/4c/0b4cb8cb3b7c0fa901adcb78348709ef_1412x642.png) ![](https://img.kancloud.cn/41/46/4146cc24e75c72ff87ef2b1940b3aee4_1168x491.png) 以上是Predicate 流程处理细节, 下面将要介绍的两个策略就是基于此抽象策略实现,只是它们使用了不同的`Predicate`实现来完成过滤逻辑以达到不同的实例选择效果。