Spring Cloud Ribbon搭建及详解 --shock wave 2

471 阅读6分钟

1、LB负载均衡(Load Balance)是什么?

简单的说就是将用户的请求平摊的分配到多个服务商,从而达到系统的HA(高可用)。

2、Ribbon本地负载均衡客户端和Nginx服务端负载均衡区别

Nginx是服务器负载均衡,客户端所有请求都会交给nginx,然后由nginx实现转发请求。即负载均衡是由服务端实现的 。 Ribbon本地负载均衡,在调用微服务接口的时候,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用技术。

补充:

1、使用ribbon实现负载均衡的时候,服务名称不能用下划线,换成中划线 2、RestTemplate 是从 Spring3.0 开始支持的一个 HTTP 请求工具,它提供了常见的REST请求方案的模版

开始搭建

引入依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

注意:在高版本spring cloud Eureka依赖中已经包含了spring cloud ribbon(我们现有版本已包含),因此无需再次引入。如过已经添加了的spring cloud Eureka依赖,不要添加该依赖,否则会遇到空指针错误。 我们首先创建3个服务,分别为client1,client2,client3。将client3和client2两个实例指向同一个微服务地址(如何配置,详情见Spring Cloud Eureka搭建及详解)

图片.png 然后我们分别在三个服务使用#bean的方式注入自己定义的RestTemplateConfig类,并开启负载均衡功能

图片(1).png client1内容:

图片(2).png client2:

图片(3).png client3:

图片(4).png 开始测试: 调用client1的getOther 测试结果: 第一次调用返回 From Port : 8703 , hello 第二次 From Port : 8704 , hello 第三次 From Port : 8703 , hello 看得出来默认为轮询方式

下面开始分析ribbon负载均衡方式 下图展示了ribbon的负载均衡类继承关系

图片(5).png 各种负载均衡方式详解: RandomRule: 随机策略

RoundRobinRule:

该策略实现了按照线性轮询的方式一次选择每个服务实例的功能。它的具体实现如下,其详细结构与RandomRule非常类似。除了循环条件不同外,就是从可用列表中获取所谓的逻辑不同。从循环条件中,我们可以看到增加了一个count计数变量,该变量会在每次循环后累加,也就是说,如果一直选择不到server超过10次,那么就会结束尝试。

RetryRule:

该策略实现了一个具备重试机制的实例选择功能。从下面的实现中我们可以看到,在其内部还定义了一个IRule对象,默认使用了RoundRobinRule实例。而在choose方法中则实现了对内部定义策略反复进行尝试的策略,若期间能够选择到实例就返回,若选择不到就根据设置的尝试时间为阈值,当超过该阈值后就返回null。

WeightedResponseTimeRule: 该策略是对RoundRobinRule的扩展,增加了根据实例的运行情况来计算权重,并根据权重来挑选实例,以达到更优的分配效果,它的实现主要有三个核心内容。 定时任务:

WeightedResponseTimeRule策略在初始化的时候会通过serverWeightTimer启动一个定时任务,用来为每个服务实例计算权重,该任务默认30秒执行一次。

权重计算:

根据LoadBalancerStats中记录的每个实例的统计信息,累加所有实例的平均响应时间,得到总平均响应时间
为负载均衡器中维护的实例清单逐个计算权重

实例选择:

获取权重区间的最后一个值,其实也就是总权重
如果总权重,低于0.01d,采用线性轮询的策略
如果总权重大于等于0.01,就产生一个权重区间内的随机数
遍历维护的权重清单,若权重大于等于随机得到的数值,就选择这个实例

ClientConfigEnabledRoundRobinRule:

该策略比较特殊,我们一般不直接使用它。因为它本身并没有实现什么特殊的处理逻辑,正如源码所示,他在内部直接引用了roundRobinRule。
虽然我们不会直接使用该策略,但是通过继承该策略,默认的choose就实现了线性轮询机制,在子类中做一些高级策略时通常有可能会存在一些无法实施的情况,那么就可以用父类的实现作为备选。

BestAvailableRule:

该策略继承自ClientConfigEnabledRoundRobinRule,在实现中它注入了负载均衡器的统计对象LoadBalancerStats,同时在具体的choose算法中利用LoadBalancerStats保存的实例统计信息来选择满足要求的实例。
它通过遍历负载据衡器中维护的所有服务shillings,会过滤掉故障的实例,并找出并发请求最小的一个,所以该策略的特性是可选出最空闲的实例。

PredicateBasedRule:

 这是一个抽象策略,它也继承了ClientConfigEnabledRoundRobinRule,从命名中可以猜出这是一个基于Predicate实现的策略,Predicate是Google Guaua Collection工具对集合进行过滤的条件接口。
它定义了一个抽象函数getPredicate来获取AbstractServerPredicate对象的实现,而在choose函数中,通过AbstractServerPredicate的chooseRandomlyAfterFiltering函数来选出具体的服务实例。从该函数的命名我们也能大致猜到他的基础逻辑:先通过子类实现的Predicate逻辑来过滤一部分服务实例,然后再以线性轮询的方式从过滤后的实例清单中选出一个。

以上是各种默认负载均衡方式的功能说明,具体可以看一哈各种负载均衡类的源代码。 那么如何变更负载均衡方式呢? 方式一:使用@bean的方式注入相关配置

图片(6).png 方式二:使用yml配置文件

ribbon:
//自定义服务列表,哪些使用此负载均衡方式
NIWSServerListClassName: com.hry.spring.cloud.consumer.ribbon.ribbonclient.self.MyDiscoveryEnabledNIWSServerList
//自定义负载均衡方式类
NFLoadBalancerRuleClassName: com.hry.spring.cloud.consumer.ribbon.ribbonclient.self.MyRule

测试: 使用@bean的方式注入,使用随机负载均衡方式 将client1设置为随机负载均衡,client2和client3不变(此时使用的是bean第二种方式进行注入,其他方式请自行尝试) 测试结果: 第一次 From Port : 8703 , hello 第二次 From Port : 8703 , hello 第三次 From Port : 8703 , hello 第四次 From Port : 8704 , hello 可以看出已经达到随机负载均衡相应效果 测试使用自定义负载均衡方式 首先继承RoundRobinRule 测试代码如下

图片(7).png 变更自定义负载均衡 方式一:

图片(8).png 方式二:同样可以使用yml配置文件的当时进行配置(详情见上面负载均衡yml配置方式) 注意: 自定义负载均衡的策略以及算法不能放在@ComponentScan所扫描的包下,不然会被所有Ribbon所共享(即所有的微服务都会使用该策略 测试 在client1主函数配置以上注释 调用client1的getOther方法

图片(9).png 可以看出测试结果已经加上了自定义的打印字段,表面自定义负载均衡方式配置成功 ribbon其他配置参数 ribbon:

系统启动之后就初始化,防止在第一次调用超时

eager-load: enabled: true

连接超时时间

ConnectTimeout: 3000

读取超时时间

ReadTimeout: 3000