1.Ribbon负载均衡流程
假设我们有一台 order-service 订单服务,两台 user-service 用户服务,当订单服务需要调用用户服务获取用户信息的时候,应该怎么分配调用哪台服务呢?
这时候就需要用到 Ribbon
组件了。
首先,我们发起远程调用的时候,指定的是需要调用的服务名称,然后我们会调用 Ribbon
组件,Ribbon 会从注册中心中拉取 user-service 服务的信息,其中就包括这两台 user-service 服务的所在地址,这时候 order-service 就获取到 user-service 服务所在的两个地址了。
那么这两个地址我们怎么选择其中一个地址进行调用呢?这时候就由 Ribbon 决定到底选择哪一台服务器进行调用,它选用的策略是轮询
。比如:找到的第一个服务器是8081,那么 order-service 最终进行调用的就是 8081 的 user-service 服务。
当然,轮询只是 Ribbon 中的其中一种负载均衡策略,那么其他还有哪些负载均衡策略呢?
2.Ribbon负载均衡策略
Ribbon 中一共封装了 7 种负载均衡策略,
1)RoundRobinRule
:简单轮询服务列表来选择服务器。
就是按照一定的顺序去调用服务的实例。比如我们刚才有 8081 和 8082 的两个 user-service 实例,假如第一次调用 8081,那么第二次就会调用 8082 了,以此类推。
2)WeightedResponseTimeRule
:按照权重来选择服务器,响应时间越长,权重越小。
其中的 ResponseTime 就是指响应时间,意思是说响应时间越长,权重就越小,被选择的概率就越低。
3)RandomRule
:随机选择一个可用的服务器。
这个比较简单,就是单纯的随机。
4)BestAvailableRule
:忽略那些短路的服务器,并选择并发数较低的服务器。
最小连接数策略。举个例子,比如我们还是有两台服务器,第一台的连接数是100,第二台是50,那这时候就会选择50的连接数对应的服务器进行连接,这就是指并发数较低的服务器,也可以理解成是选择一个空闲比较多的服务器进行连接。
5)RetryRule
:重试机制的选择逻辑。
首先,还是会按照轮询的方式选择服务,然后进行远程调用。但是,假如某些服务实例为null,或者某些服务实例已经宕机失效了,它就会按照指定的时间进行不断地重试,来去获取这个服务,这个就是重试机制的选择逻辑。
6)AvailabilityFilteringRule
:可用性敏感策略,先过滤非健康的,再选择连接数较小的实例。
比如说我们有三台服务器,如果第一台服务器已经宕机了,很显然就不选择第一台服务器了,然后再从第二、三台服务器中选择连接数比较小的实例,比如第二台服务器的连接数是100,第三台服务器的连接数是50,那么很显然就要去选择第三台服务器。
7)ZoneAvoidanceRule
:默认策略,以区域可用的服务器为基础进行服务器的选择。使用 Zone 对服务器进行分类,这个 Zone 可以理解为一个机房、一个机架等。而后再对 Zone 内的多个服务做轮询。
意思是说,服务很多的时候,就会存在很多机房,比如一个在上海,一个在北京。假如服务的调用方也在北京,那么就会优先选择北京的机房服务器进行连接,就近原则。一般情况下,比如说我们没有区域的概念,那么这时候还是会根据轮询的方式来完成调用。
以上就是 Ribbon 最常见的七种负载均衡策略,标红的是面试的时候最好能给面试官陈述出来的部分。
3.自定义负载均衡策略如何实现
我们可以自己创建类实现 IRule
接口,然后再通过配置类或配置文件配置即可,通过定义 IRule 实现可以修改负载均衡规则,有两种方式。
假如我们有一个 order-service 订单服务调用 user-service 用户服务,用户服务有 8081 和 8082 两个节点。
现在我们想实现自定义的负载均衡策略,我们都是在服务的发起方 order-service 进行配置的。
第一种方法: 我们可以加一个配置类,在配置类中设置一个返回值 IRule
,我们可以直接将七种负载均衡策略中的其中一种进行返回。
第二种方式: 我们可以在 yaml
文件中进行配置。
user-service:
ribbon:
NFLoadBalanceRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则
这两种配置方式有什么不同?
-
第一种通过配置类自定义注入 Bean 的方式,是全局生效的。
意思是只要是 order-service 服务采用 Ribbon 进行的负载均衡调用都是使用的自定义负载均衡策略。
-
第二种通过 yaml 配置的方式,是局部生效的。
意思是在 order-service 服务采用 Ribbon 进行负载均衡的时候,只有请求 user-service 服务的请求是使用的自定义负载均衡策略。
4.总结
1)项目负载均衡如何实现?
微服务的负载均衡主要使用了一个组件 Ribbon
,比如,我们在使用 feign 远程调用的过程中,底层的负载均衡就是使用了 Ribbon。
2)Ribbon负载均衡有哪些?
RoundRobinRule
:简单轮询服务列表来选择服务器。WeightedResponseTimeRule
:按照权重来选择服务器,响应时间越长,权重越小。RandomRule
:随机选择一个可用的服务器。ZoneAvoidanceRule
:默认,区域敏感策略,以区域可用的服务器为基础进行服务器的选择。使用 Zone 对服务器进行分类,这个 Zone 可以理解为一个机房、一个机架等。而后再对 Zone 内的多个服务做轮询。
3)自定义负载均衡策略如何实现?
提供了两种方式:
① 创建类实现 IRule
接口,可以指定负载均衡策略(全局生效)。
② 在客户端的 yaml
配置文件中,可以配置某一个服务调用的负载均衡策略(局部生效)。
5.思考
1)如果通过 feign 调用本服务,会负载均衡吗?
答案:会。因为即使调用本服务,也会先从注册中心获取服务所有节点的地址信息去负载均衡。
比如,我们写一个下面这样的 Controller 来动态打印当前服务的端口:
@RestController
@RequestMapping("/demo")
public class DemoController {
@Value("${server.port:}")
private String port;
@Autowired
private DemoFeignClient demoFeignClient;
@GetMapping("/test")
public Result<Object> test() {
String data = "This is a test! port:" + port;
return Result.succeed().setData(data);
}
@GetMapping("/feignTest")
public Result<Object> feignTest() {
return demoFeignClient.test();
}
}
我们再写一个 feign client 类来调用本服务的接口:
@FeignClient(value = "springboot-feign")
public interface DemoFeignClient {
@GetMapping("/demo/test")
Result<Object> test();
}
当我们用 8081 和 8082 端口来启动两个实例后,调用接口:http://localhost:8081/demo/feignTest,可以发现返回的端口实际上是轮询打印的:
整理完毕,完结撒花~ 🌻