1.Ribbon是什么?
Ribbon是Netflix发布的负载均衡器,它有助于控制HTTP和TCP的客户端的行为。为Ribbon配置服务提供者地址后,Ribbon就可基于某种负载均衡算法,自动地帮助服务消费者去请求。Ribbon默认为我们提供了很多负载均衡算法,例如轮询、随机等。当然,我们也可为Ribbon实现自定义的负载均衡算法。
在Spring Cloud中,当Ribbon与Nacos配合使用时,Ribbon可自动从Nacos Server获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。展示了Ribbon与Nacos配合使用时的架构。
2.源码跟踪
为什么我们只输入了service
名称就可以访问了呢?之前还要获取ip和端口。显然有人帮我们根据service名称,获取到了服务实例的ip和端口。它就是LoadBalancerInterceptor
我们进行源码跟踪:
继续跟入execute方法:发现获取了8001端口的服务
org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient
如果再跟下一次,发现获取的是8002
2.负载均衡策略
Ribbon默认的负载均衡策略是简单的轮询,我们可以测试一下:
编写测试类,在刚才的源码中我们看到拦截中是使用RibbonLoadBalanceClient
来进行负载均衡的,其中有一个choose
方法,是这样介绍的:
现在这个就是负载均衡获取实例的方法。我们对注入这个类的对象,然后对其测试:
package com.bruceliu.test;
import com.bruceliu.SpringcloudDemoConsumerApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author bruceliu
* @create 2019-05-04 11:33
* @description 负载均衡算法测试
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringcloudDemoConsumerApplication.class)
public class LoadBalanceTest {
@Autowired
RibbonLoadBalancerClient client;
@Test
public void test1(){
for (int i = 0; i <10 ; i++) {
ServiceInstance instance = this.client.choose("SPRINGCLOUD-DEMO-SERVICE");
System.out.println(instance.getHost() + ":" + instance.getPort());
}
}
}
运行结果:
符合了我们的预期推测,确实是轮询方式。
我们是否可以修改负载均衡的策略呢?继续跟踪源码,发现这么一段代码:
我们看看这个rule是谁:
这里的rule默认值是一个RoundRobinRule
,看类的介绍:
这不就是轮询的意思嘛。
我们注意到,这个类其实是实现了接口IRule的,查看一下:
定义负载均衡的规则接口。
它有以下实现:
SpringBoot也帮我们提供了修改负载均衡规则的配置入口:
SPRINGCLOUD-DEMO-SERVICE:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
格式是:{服务名称}.ribbon.NFLoadBalancerRuleClassName
,值就是IRule的实现类。
再次测试,发现结果变成了随机:
2.1 Ribbon核心组件IRule(面试题)
策略名称 | 策略对应的类名 | 实现原理 |
---|---|---|
轮询策略(默认) | RoundRobinRule | 轮询策略表示每次都顺序取下一个 provider,比如一共有 5 个provider,第 1 次取第 1 个,第 2次取第 2 个,第 3 次取第 3 个,以此类推 |
权重轮询策略 | WeightedResponseTimeRule | 1.根据每个 provider 的响应时间分配一个权重,响应时间越长,权重越小,被选中的可能性越低。2.原理:一开始为轮询策略,并开启一个计时器,每 30 秒收集一次每个 provider 的平均响应时间,当信息足够时,每个 provider附上一个权重,并按权重随机选择provider,高权越重的 provider会被高概率选中。 |
随机策略 | RandomRule | 从 provider 列表中随机选择一个provider |
最少并发数策略 | BestAvailableRule | 选择正在请求中的并发数最小的 provider,除非这个provider 在熔断中。 |
在“选定的负载均衡策略”基础上进行重试机制 | RetryRule | 1.“选定的负载均衡策略”这个策略是轮询策略RoundRobinRule 2.该重试策略先设定一个阈值时间段,如果在这个阈值时间段内当选择 provider 不成功,则一直尝试采用“选定的负载均衡策略:轮询策略”最后选择一个可用的provider |
可用性敏感策略 | AvailabilityFilteringRule | 过滤性能差的 provider,有 2种:第一种:过滤掉在 eureka 中处于一直连接失败 provider 第二种:过滤掉高并发的 provider |
区域敏感性策略 | ZoneAvoidanceRule | 1.以一个区域为单位考察可用性,对于不可用的区域整个丢弃,从剩下区域中选可用的provider2.如果这个 ip 区域内有一个或多个实例不可达或响应变慢,都会降低该 ip 区域内其他 ip 被选中的权重。 |
2.2.修改访问服务的算法方式
方式一:修改代码更换负载均衡策略
第一步:新建一个不会被@ComponentScan组件扫描到的包,如:com.rules
第二步:在该包下新建自己的负载均衡算法的规则类
第三步:主启动类上添加注解:@RibbonClient
package com.rules;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @BelongsProject: MicroService
* @BelongsPackage: com.rules
* @CreateTime: 2020-11-18 16:50
* @Description: TODO
*/
@Configuration
public class MyLoadBalanceRule {
/**
* @desc 自定义负载均衡规则,默认是轮询规则
* @return
*/
@Bean
public IRule myRule(){
//return new RandomRule(); // 改为随机算法规则
return new RoundRobinRule(); // 轮询
}
}
@EnableEurekaClient //开启客户端
@SpringBootApplication
@RibbonClient(name = "PRODUCT-SERVICE",configuration = MyLoadBalanceRule.class)
public class ProtalApp80 {
public static void main(String[] args) {
SpringApplication.run(ProtalApp80.class,args);
}
}
注意: 这里这个类不能配置到SpringBoot启动类的同级别目录下以及子目录下,为什么呢?因为Ribbon的配置必须用@Configuration注解标识,并且不能被@Component注解或者@SpringBootApplication(因为里面包含了@Component)扫描到。因为如果被@ComponetScan扫描到会导致所有的RibbonClient都去共享这个配置。
方式二:修改配置文件更换负载均衡策略
第二种方式在application.properties中设置分配的策略
springcloud-alibaba-provider:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
'springcloud-alibaba-provider’是调用的服务的名称,后面的组成部分是固定的。
同时注释掉方式一中的内容