目录:
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/ac6aa093d6384d16a2dbc6cd044eb7d2.gif#pic_center)
作者简介 :一只大皮卡丘,计算机专业学生,正在努力学习、努力敲代码中! 让我们一起继续努力学习!
该文章参考学习教材为:
《Spring Cloud微服务架构开发》 黑马程序员 / 编著
文章以课本知识点 + 代码为主线,结合自己看书学习过程中的理解和感悟 ,最终成就了该文章文章用于本人学习使用 , 同时希望能帮助大家。
欢迎大家点赞👍 收藏⭐ 关注💖哦!!!(侵权可联系我,进行删除,如果雷同,纯属巧合)
- 微服务架构中,负载均衡 是一个必不可少的技术。负载均衡 决定着 整个服务集群 的 性能和 稳定。
- Spring Cloud 体系中加入了 Netfix公司 ( 网飞公司 ) 的很多优秀产品,其中一个就是实现客户 负载均衡 的工具 : Ribbon。下面将对 客户端负载均衡工具 : Ribbon 进行讲解。
1. 什么是 “负载均衡” ? ( 通过 “负载均衡” 可以将 “用户请求” “分发” 到 不同的服务器,以此来提高 “性能” 和 “可靠性” )
负载均衡是 “高可用” 网络基础架构 的一个关键组成部分,有了负载均衡,我们通常 可以部署多台 “应用服务器”,然后
通过负载均衡 将 “用户的请求” "分发"到 不同的服务器用来 提高网站、应用、数据库或其他服务的 性能 以及 可靠性。---- 通过"负载均衡"可以 将用户的"请求" "分发"到 不同的服务器 ,以此来 提高"性能" 和 “可靠性”。
---- 通过 “负载均衡” 可以 部署多台 "服务器"。
下面我们来看一个 不使用 “负载均衡” 的 Web 架构,如下图所示 :
上图中,客户端之间通过因特网与 Web服务器端 “相连”。
① 假想如果 Web 服务器 “宕机” ,用户访问网站时就将 “得不到” 任何响应,出现 单点故障问题。 ② 即使服务器可以正常工作,如果 很多用户同时访问服务器,数据 超过服务器的 处理能力,就会出现 响应速度慢 或者 无法连接 的情况,这也是用户无法接受的。引入负载均衡可以有效 解决上述问题,它可以将 负载 ( 工作任务 ) 进行 平衡,分摊到 “多个” 执行单元 ( 如 Web服务器、FTP服务器、企业关键应用服务器和其他主要任务服务器等上运行,协同完成工作任务。
2. “负载均衡” 的 分类 ?
负载均衡 分为 “硬件” 负载均衡 和 “软件” 负载均衡两种,具体介绍如下 :
(1) “硬件” 负载均衡 的 解决方案就是直接在服务器 和 外部网络 之间 安装 “负载均衡设备”,通常这种设备称为 负载均衡器。
这样由 专门的设备 完成专门的任务,负载均器 “独立于” 操作系统之外,整体性能 得到大幅提高。加上多样化的 负载均衡策略,智能化的流量统计,“硬件” 负载均衡 的 解决方案 可达到 最佳 的 负载均衡效果。
(2) “软件” 负载均衡 的 解决方案是指在 一台 或 多台服务器相应的 操作系统上安装一个或 多个 "附加软件"来实现负载均衡,
如 DNS Load Balance、CheckPoint Firewall-1 ConnectControl 等。它的 优点是 基于特定环境、配置简单、使用灵活、成本低廉,可以 满足一般的负载均衡需求。无论哪种负载均衡策略,都是为了系统高可用、缓解网络压力以及扩容机器处理能力。
下面我们来看一个 使用 “负载均衡” 的 Web架构,具体如下图所示 :
在上图所示架构中,负载均衡器 会 维护一个可用的 “服务清单”,通过 心跳检测来 剔除故障的 服务端节点 以 保证服务清单 中都是 可以正常访问的 服务器。当客户端借助网络 发送请求 到 负载均衡器时,负载均衡器会按照 “某种算法”,从维护的服务清单里面"选择"
一个服务器,并将 客户端请求 "转发"到指定的服务器,从而提高 系统 的 可用性 和 稳定性。
3. 认识 Ribbon :
3.1 Ribbon 的 含义
- Ribbon是 Netflix 公司的一款用于 客户端 负载均衡 的 开源软件工具。它在集群中为 各个客户端的 通信 提供了 支持,有助于
控制 HTTP 和 TCP 客户端 的 行为,提供了很多 负载均衡 的 算法,例如轮询、随机算法等,同时也可以实现自定义的算法。
3.2 Ribbon 的 实现 ( ①与 “RestTemplate” 相结合 ②与 “Feign” 相结合 )
在 Spring Cloud 构建的 微服务架构 中 Ribbon 作为 服务消费者 的 负载均衡器,有 两种 “使用方式” ( Ribbon 的 “实现方式” ):
(1) 一种是 与 RestTemplate 相结合。
(2) 另一种是 与 Feign 相结合。Feign已经默认集成了Ribbon。Ribbon 包含很多 “子模块”,但很多子块 没有用于生产环境。 目前 用于生产的Ribbon 的 子模块 具体如下 :
① mibbon-core : 包括定义 负载均衡接口、客户端接口、内置 的 负载均衡实现接口 等的 API。
② ribbon-eureka : 提供 Eureka客户端 实现 "负载均衡"的 API。
③ ribbon-httpclient : 对 Apache的 HttpClient 进行封装。该模块提供了 含有 “负载均衡” 功能 的 REST客户端。、在Spring Cloud 中,当 Ribbon ( 负载均衡 ) 和 Eureka ( 服务的注册与发现 ) 配合使用的时候,Ribbon 可从 Eureka Server 中获取 服务提供者 “地址列表”,并 基于 “负载均衡算法” ,请求 其中一个 服务提供者实例 。
Ribbon 整合 Eureka 的 结构示例 如下图所示 :
由上图可见,该结构包含 一个 ① Eureka服务器,② 3个服务提供者以及 ③ 一个含有Ribbon 的 服务消费者。
3个服务提供者向 Eureka服务器 "注册服务",当多个URL向 服务消费者 发起请求时,基于Ribbon的 负载均衡器 能够有效地将请求分摊到不同的机器上。
3.3 Nginx 与 Zookeeper 比较
Nginx 和 Zookeeper 也是 可以作为 “负载均衡器” 使用 的,具体介绍如下 :
(1) Nginx是著名的 反向代理服务器,也被广泛地 作为 “负载均衡器” 使用。它的负载均衡配置非常简单,Nginx 中配置
多个Web服务器,用户访问 Nginx 时,就会 “自动被分配” 到 “某个Web 服务器”。
(2) ZooKeeper 是 “分布式协调服务” 框架,有时 也被用来作为 “负载均衡器” 使用。ZooKeeper作为一个服务的注册中心,其中登记了每个服务。每台服务器知道自己 “属于哪个服务”,在 服务器启动时,自己向所属服务进行登记。
4. 第一个 Ribbon 实例 :
- 在 服务 “注册与发现“ 框架 : Eureka框架 已经实现了Eureka高可用,理论上使得微服务架构已经很完美了。但是, 考虑到机器自身硬件条件的限制,面对 流量高峰,系统同样还会存在 宕机 等情况。此时,如果 使用 Ribbon “整合” Eureka “实现负载均衡”,将用户请求 “分摊到” 多个服务器上,就能大幅减轻访问服务压力,使系统达到更好的负载能力。
- 下面我们将在 服务 “注册与发现“ 框架 : Eureka框架 搭建的 Eureka 集群 “基础上” 进行 改造,具体步骤如下 :
4.1 改造 “服务提供者”
① 在 “服务提供者” 中 添加 Service层,创建 PortController控制器类
( 前提 : 在 服务 “注册与发现“ 框架 : Eureka框架 敲的项目的 基础上进行关于 Ribbon 的开发 )
我们将在 服务消费者上"集成Ribbon" 实现 “客户端负载均”。为了验证 服务消费者 调用的是 “哪个服务提供者” 的 服务,下面我们对 服务提供者进行改造。改造后的 服务提供者 提供了"/port" API,用于 返回服务提供者的端口号。
在 ① 项目 : eureka-provider ( “第一个” 服务提供者 ) 和 ② eureka-provider-another ( “第二个” 服务提供者 ) 中 新建 controller包 ( 两个 “服务提供者” 项目中都加 ),并创建PortController类,该类 能够 返回当前项目 的 端口号。具体代码如下所示 :
PortController.java :
import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; /* @ResponseBody注解 : ①将方法的返回值转换为指定类型存入到"响应体"中响应给前端 : 如果返回值为String类型,这个字符串会直接写入"响应体"中响应给前端( 不使用该注解时,String类型的返回值可以返回一个视图页面的,但现在没这个效果了 ) 如果返回值为"对象类型",会默认采用 MappingJackson2HttpMessageConverter 将该对象转换为"JSON格式的字符串",后写入"响应体"中响应给前端。 */ @ResponseBody @Controller //将该类加入到IOC容器中 public class PortController { //返回当前项目的"端口号" @Value("${server.port}")//获取"全局配置文件"中的属性值,并将该属性值注入到下面这个属性中 String port; @RequestMapping("/port") public String getPort() { return "Hello World,I'm from port: " + port; } }
4.2 搭建含有 Ribbon 的 “服务消费者” :
② 创建名称为 :eureka-ribbon-client 的Spring Boot 项目
使用 Spring Initializr 方式创建一个名称为 eureka-ribbon-client 的 Spring Boot 项目。这里将 Group 命名为 com.myh , 将 Artifact 命名为 eureka-ribbon-client , 添加 Eureka Client、 Ribbon 和 Web 的 这 三个依赖。项目创建好后的 pom.xml文件 代码 如下所示 :
pom.xml :
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <!-- SpringBoot的版本为:2.1.7.RELEASE --> <version>2.1.7.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.myh</groupId> <artifactId>eureka-ribbon-client</artifactId> <version>0.0.1-SNAPSHOT</version> <name>eureka-ribbon-client</name> <description>eureka-ribbon-client</description> <properties> <java.version>1.8</java.version> <!-- Springcloud的版本为:Greenwich.SR2 --> <spring-cloud.version>GreenWich.SR2</spring-cloud.version> </properties> <dependencies> <!-- 引入了 eureka-client 的jar包 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 引入了 Ribbon(客户端的"负载均衡器") 依赖启动器 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <releases> <enabled>false</enabled> </releases> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <releases> <enabled>false</enabled> </releases> </pluginRepository> </pluginRepositories> </project>
③ “全局配置文件中” 配置信息
在 全局配置文件 : application.yml中进行相关配置,包括指定 应用名称、端口号 、服务注册地址 等信息。具体代码如下所示 :
application.yml :
spring: application: name: eureka-ribbon-client #指定该应用的名为 : eureka-ribbon-client / 端口名称配置 server: port: 8764 #指定该应用的端口号为 : 8764 eureka: client: register-with-eureka: true #表示将自己 "注册" 到"Eureka服务注册中心 / Eureka服务端" (默认值为true,所以该属性可省略不配置) fetch-registry: true #表示 "从" EurekaSever 中获取 "注册信息" (默认值为true,所以该属性可省略不配置) service-url: defaultZone: http://localhost:7000/eureka/ #指定EurekaServer(服务注册中心)的地址
④ 在 “项目启动类” 中添加注解,开启Eureka Client 功能
在 “项目启动类” 中 激活 Bureka Client 的 相关配置 : 在项目启动类中 添加 @EnableEuekaClient注解,开启 Eureka Client 功能,具体代码如下所示 :
⑤ 创建 “RibbonConfg 配置类” ( 通过 与 “RestTemplate” 相结合来实现 “Ribbon负载均衡” )
创建配置类,在 项目中新建 config包,并在该包下创建 RibbonConfg类。在 RibbonConfg类中注入 restTemplate 的 Bean 对象,并在 Bean 对象中加上 @LoadBalanced 注解。具体代码如下所示 :
RibbonConfig.java :
import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration //比较该类为"配置类" public class RibbonConfig { //Ribbon : 客户端"负载均衡器" 的 配置类 @Bean //将该方法的返回值对象加入到IOC容器中 @LoadBalanced // 该注解的作用 : 让 RestTemplate对象/RestTemplate实例 具备"负载均衡"的能力 public RestTemplate restTemplate(RestTemplateBuilder builder) { //返回一个被 @LoadBalanced注解作用的 RestTemplate示例/RestTemplate对象 //返回一个 具备 "负载均衡"能力的RestTemplate对象 return builder.build(); } }
在上面的代码中,使用 @Confguration注解将 RibbonConfg类 “标注为” 配置类,@Bean注解 的作用 : 将 restTemplate( ) 的返回值 : RestTemplate 对象 加入到 IOC容器中,@LoadBalanced 注解的作用 :让 RestTemplate对象 具备 “负载均衡” 的 能力。
⑥ 创建 Service层 , 创建 RibbonService业务类
在 项目中新建 service包,并在该包下创建一个 RibbonService类。在 RibbonService 类的 hi( )方法中使用restTemplate对象 “调用” eureka-client 的 API。具体代码如下所示 :
RibbonService.java :
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; @Service //加入ioc容器中 public class RibbonService { //获得访问的"服务提供者"的端口号信息 @Autowired RestTemplate restTemplate; public String hi() { /* getForObject()方法用于发起Get请求, 第一个参数设置 : 请求的url ; 第二个参数指定 "返回结果" 的 Java类型,告诉 RestTemplate 将"响应体中的内容"转换为"指定类型"的对象。 通过url请求访问到 "服务提供者"项目中的/port路径中,获得访问的"服务提供者"的端口信息 ---(如果每次访问到的端口不是一样的,说明"负载均衡成功了") */ return restTemplate.getForObject("http://eureka-provider/port",String.class); //String.class : 将响应体中内容转换为String类型 } }
⑦ 创建 controller层 , 创建 RibbonService业务类
在项目中新建 controller 包,在该包下新建一个 RibbonController 的类。在该类上添加 @RestController 注解,
类中写一个 hi( )方法 , 通过该方法调用 RibbonService 的 hi( )方法。具体代码如下所示 :import com.myh.eurekaribbonclient.service.RibbonService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; @RestController // = @@ResponseBody注解 + @Controller注解 public class RibbonController { //该类为控制层类,可调用业务层中的代码 @Autowired RibbonService ribbonService; @RequestMapping("/hi") public String hi() { //获得RibbonService业务类中的hi()方法的内容 return ribbonService.hi(); } }
4.3 测试运行
① 启动 eureka-server 和 eureka-server-another 这两个服务器( 服务器注册中心 ) , ② 启动 eureka-provider 和 eureka-provider-another 这两个 “服务提供者”, ③ 启动 服务消费者 : eurek-ribbon-client ( 该服务消费者中 配置了 Ribbon负载均衡器 )。
在浏览器上访问 http://server1:7000 和 http://server2:7009 ( 这两个为 “服务注册中心” 的 访问url )。无论访问 “哪个Eureka Server”,Eureka Server 的
注册实例都是一样的,效果如下两图所示 :
从上两图看出,"两个"服务提供者和 "一个"服务消费者已经全部成功注册到 Eureka ( Eureka Server服务注册中心 )上,实现了高可用。为了演示含有Ribbon的服务消费者 的 负载均衡的效果,使用浏览器多次访问 :
http://localhost:8764/hi ( localhost 为 主机名,8764为 端口号 , /hi 为 url请求 , 请求该项目中控制层中的 /hi路径下的对应的方法 )浏览器页面 访问效果如下图 所示 :
从上面两个图 可以看出,当访问 http://localhost:8764/hi 时,浏览器页面会轮流显示 “两个服务提供者” 的 端口号,说明负载均衡起了 效果,负载均衡器会轮流请求 两个服务提供者 中的 “hi”接口。
5. Ribbon 的工作原理
前面我们 使用Ribbon "实现负载均衡"时,基本用法是注入一个 RestTemplate,并使用@LoadBalanced注解 标注RestTemplate,从而使 RestTemplate 具备 负载均衡 的 能力。
当Spring容器启动时,使用 @LoadBalanced注解 修饰的 RestTemplate 会被 添加到 “拦截器” 中,拦截器 中使用了
LoadBalancerClient “处理请求”,从而 达到 负载均衡的 目的 。那么 LoadBalancerClient 内部是如何做到的呢?
下面我们通过 源码分析 的方式来 剖析 Ribbon负载均衡 的 工作原理。LoadBalancerClient 是Spring Cloud 提供的一个非常重要的接口,它 继承于 : ServicelnstanceChooser接口,该接口的 实现类 是 : RibbonLoadBalanceClient,它们之间的 关系如下图所示 :
为了大家更好地理解中所示接口及其实现类的实现细节,我们先来查看 LoadBalancerClient 的 部分源码,具体代码如下 :
public interface LoadBalancerClient extends ServiceInstanceChooser { <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException; <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException; URI reconstructURI(ServiceInstance instance, URI original); }
上述源码中,LoadBalancerClient 提供的 “两个” execute( )方法 用于**执行请求** , reconstructURI ( )方法用于重构 URL。
继续査看 LoadBalancerClient 继承 的 ServiceInstanceChooser接口 的 源码,具体代码如下 :
public interface ServiceInstanceChooser { ServiceInstance choose(String serviceId); }
上述源码中,ServicelnstanceChooser接口定义了一个choose( )方法。该方法用于根据 serviceId选择一个服务实例,即通过服务名 “选择” 服务实例。
RibbonLoadBalanceClient 是 LoadBalancerClient 的 实现类,它用来 执行最终的负载均衡请求 。RibbonLoadBalanceClient 中的 choose( )方法用于选择具体的 服务实例,其内部是通过 getServer( )方法交给ILoadBalancer接口 完成的。
ILoadBalancer 是一个接口,该接口定义了一系列 “实现负载均衡” 的 方法。IoadBalancer 接口的 实现类结构如下图所示 :
查看 BaseLoadBalancer 和 DynamicServerListLoadBalancer 源码,默认情况下实现了以下配置。
- (1) IClientConfg clientConfg : 用于配置 “负载均衡客户端”。默认实现类 是 DefaultClientConfglmpl。
- (2) IRule rule : 用于配置 负载均衡的 策略,默认使用的是 RoundRobinRule 策略,也就是轮询策略。
- (3) IPing ping : 用于检查当前服务 “是否有响应”,从而判断当前服务 “是否可用”。默认实现类是 DummyPing。该 实现类的isAlive( )方法 的 返回值是 true,即 默认所有服务实例都是可用的。
- (4) ServerList serverList : 用于获取所有 Server注册列表信息。ServerList 的 实现类是DiscoveryEnabledNIWSServerList。该类定义的 obtainServersViaDiscovery( )方法根据 eurekaClientProvider.get()方法获取 EurekaClient,再根据 EurekaClient 获取 “服务注册列表信息”。EurekaClient的 实现类是 DiscoveryClient。DiscoveryClient 具有服务注册、获取服务注册列表 等功能。
- (5)ServerListFilter flter : 定义了根据 配置过滤或 者动态获取符合条件的 服务列表,默认实现类是ZonePreferenceServerListFilter。该策略能够“优先过滤出” 与请求调用方处于同区域的服务实例。
综上所述,使用 RibbonLoadBalanceClient 实现"负载均衡"时,会从 EurekaClient 获取 “服务列表信息”,然后根据 IPing 判断服务 “是否可用”。如果服务可用,就会根据 IRule 选择 "负载均衡策略",否则会 “重新获取” 服务清单。
了解了 LoadBalancerClient 负载均衡功能后,那么ResrTemplate 添加 @LoadBalanced 注解后 为什么会被拦截呢?
这是因为 LoadBalancerAutoConfiguration类维护了一个被 @LoadBalaneed 注解修饰的 ResTemplate 列表,在
初始化过程中,通过调用 customizer.customize( resTemplate )方法 为 RestTemplate 添加了
LoadBalancerlnterceptor拦截器,该拦截器中的方法将 远程服务调用的方法 交给了 LoadBalancerClient 去处理,
从而达到了 负载均衡的目的。
6. Ribbon 负载均衡策略
默认情况下,Ribhon 使用的 负载均衡策略是 轮询策略。实际上,Ribbon 提供了 很多 负载均衡算法 ,其中 IRue 接口就是 所有负载均衡算法 的 父接口 , 它的实现类结构 如下图所示 :
在上图中,AbstractLoadBalancerRule是 负载均衡策略的 抽象类。该抽象类中 定义了负载均衡器 : IoaderBalancer对象 ,对象能够 在具体 实现 "选择服务策略"时,获取到一些负载均衡器中维护的信息,该信息会作为 选择 "服务策略"时的分配依据,并以此设计一些算法来实现针对特定场景的高效策略。
在上图中,各个实现类实现了一种负载均衡算法,关于这些实现类的具体介绍如下 :
- RoundRobinRule :
实现了按 “照线性轮询” 的方式 依次选择服务 的功能。- WeightedResponseTimeRule :
它是对 RoundRobinRule 的扩展,会根据平均响应时间 “计算” 所有服务的 “权重”,响应时间越快,服务权重越大,被选中的概率越高。- ZoneAvoidanceRule :
它是 PredicateBasedRue 的具体实现类。其内部通过使用 ZoneAvoidancePredicate 和 AvailabilityPredicate 判断 ”是否选择“ 某个服务,前者用于判断服务所在区域的性能 “是否可用”,后者用于 “过滤掉” 连接数过多的服务。- AvailabilityFilteringRule :
使用 AvailabilityPredicate 过滤 由于 多次访问出现故障而处于断路器跳闸状态的服务,还有 并发的连接数 "超过阈值" 的 服务,然后对 剩余的服务列表进行 轮询。- BestAvailableRule :
用于 先过滤掉多次访问出现故障而处于断路跳闸状态的服务,然后选择一个 并发量最小的服务。- RetryRule :
该策略实现了一个 具备 “重试功能”的 服务选择功能,其内部会"先按照轮询策略" 获取服务,如果获取失败就在
指定时间内重试,获取可用服务。- RandomRule :
该策略实现了从服务清单中随机选择一个服务的功能。- ClientConfgEnableRoundRobinRule :
该类是一个 抽象类。该类本身没有实现特殊的处理逻辑,我们 也不会直接使用该策略,但是通过使用 BestAvailableRule 和继承该策略 默认实现了 线性轮询。它的内部定义了一个RoundRobinRule 策略。- PredicateBasedRule : 继承了ClientConfgEnableRoundRobinRule,其内部会先通过
chooseRoundRobinAferFiltering( ) 方法 “筛选服务清单”,然后以 线性轮询的方式从 过滤后的服务清单中选择一个服务。