负载均衡

Ribbon

Springcloud Ribbon实现的是一套客户端负载均衡的工具
主要功能是提供客户端的软件负载均衡算法和服务调用
在客户端的配置文件中列出后面服务提供方后面所有的机器,Ribbon会自动根据某种规则(比如通过轮训算法,或者随机连接等等)去连接这些机器。
通过自定义Bean的方式,我们很容易配置Ribbon使用的负载轮询算法

Ribbon和Nginx

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

集中式LB和进程内LB

集中式LB:服务的消费方和服务的提供方之间使用独立的LB设施(可以是硬件也可以是软件),比如Nginx,由该设施进行负责将访问的请求通过某种转发策略转发到服务的提供方。
进程内LB:将LB的逻辑集成到消费方,由消费方自身进行负载均衡

Ribbon在工作的时候分为以下两个步骤:

  • 第一步选择EurekaServer,获取服务信息列表,会优先选择负载较少的EurekaServer
  • 第二步通过用户指定的策略,在Server取到的服务信息列表中选择一个作为请求的地址

默认自带的负载规则

  • RoundRobinRule轮询
  • RandomRule随机
  • RetryRule先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重
  • WeightedResponseTimeRule对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择
  • BestAvailableRule会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
  • AvailabilityFilteringRule先过滤掉故障实例,再选择并发较小的实例
  • ZoneAvoidanceRule默认规则,复合判断server所在区域的性能和server的可用性选择服务器

    替换默认的负载规则

    image.png
    配置的过程就是我们自定义一个Bean(也就是他自带规则对应的一些类),然后来替换掉默认负载规则。
    配置的过程中,自定义配置类不能放在ComponentScan所能扫描到的包下
    不然我们的自定义配置类会被所有的Ribbon客户端所共享,失去了特殊化定制的目的
    image.png

    1. /**
    2. * Created By Intellij IDEA
    3. *
    4. * @author ssssheep
    5. * @package org.example.myrule
    6. * @datetime 2022/8/10 星期三
    7. */
    8. @Configuration
    9. public class MySelfRule {
    10. @Bean
    11. public IRule rule() {
    12. // 采用随机算法
    13. return new RandomRule();
    14. }
    15. }

    在主启动类上添加注解@RibbonClient

    1. /**
    2. * Created By Intellij IDEA
    3. *
    4. * @author ssssheep
    5. * @package org.example.springcloud
    6. * @datetime 2022/8/9 星期二
    7. */
    8. @SpringBootApplication
    9. @EnableEurekaClient
    10. @RibbonClients(
    11. @RibbonClient(name = "CLOUD_PAYMENT_SERVICE", configuration = MySelfRule.class)
    12. )
    13. public class OrderApplication80 {
    14. public static void main(String[] args) {
    15. SpringApplication.run(OrderApplication80.class, args);
    16. }
    17. }

    服务调用

    介绍

    Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka, as well as Spring Cloud LoadBalancer to provide a load-balanced http client when using Feign.

Feign是一个声明式的网络服务客户端。它使编写Web服务客户端更容易。要使用Feign,需要创建一个接口并对其进行注释。它有可插拔的注解支持,包括Feign注解和JAX-RS注解。Feign还支持可插拔的编码器和解码器。Spring Cloud增加了对Spring MVC注释的支持,并支持使用Spring Web中默认使用的HttpMessageConverters。Spring Cloud集成了Ribbon和Eureka,以及Spring Cloud LoadBalancer,以便在使用Feign时提供一个负载均衡的http客户端。
简单来说就是对RESTful的HTTP客户端进行了封装,并内置了Ribbon进行负载均衡调用
OpenFeign是SpringCloud在Feign的基础上支持了SpringMVC的相关注解,使得Feign可以解析@RequestMapping注解下的接口,然后通过动态代理的方式来产生实现类,实现调用远端接口

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-openfeign</artifactId>
  4. </dependency>

新建模块

新建模块:cloud-consumer-feign-order80

  1. server:
  2. port: 80
  3. eureka:
  4. client:
  5. register-with-eureka: false
  6. service-url:
  7. defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

建Service

由于我们在Service中,实际调用的应该是远端的服务
因此我们肯定不再像单体应用那样,去写实现类以及dao层接口
而是直接通过http实现rpc调用

  1. /**
  2. * Created By Intellij IDEA
  3. *
  4. * @author ssssheep
  5. * @package org.example.springcloud.service
  6. * @datetime 2022/8/10 星期三
  7. */
  8. @Component
  9. // 表明这个接口是用来调用远端CLOUD-PAYMENT-SERVICE服务的
  10. @FeignClient(value = "CLOUD-PAYMENT-SERVICE")
  11. public interface PaymentFeignService {
  12. // 使用SpringMVC的注解
  13. @GetMapping("/payment/get/one/{id}")
  14. ApiResult getPaymentById(@PathVariable("id") Long id);
  15. @GetMapping("/payment/timeout")
  16. String timeoutTest();
  17. }

建Controller

在Controller中将刚刚编写的Service注入进来即可

  1. /**
  2. * Created By Intellij IDEA
  3. *
  4. * @author ssssheep
  5. * @package org.example.springcloud.controller
  6. * @datetime 2022/8/10 星期三
  7. */
  8. @RestController
  9. @RequestMapping("/order/feign")
  10. public class OrderFeignController {
  11. @Autowired
  12. private PaymentFeignService paymentFeignService;
  13. @GetMapping("/get/{id}")
  14. public ApiResult getPaymentById(@PathVariable("id") Long id) {
  15. return paymentFeignService.getPaymentById(id);
  16. }
  17. @GetMapping("/timeout")
  18. public String timeoutTest() {
  19. return paymentFeignService.timeoutTest();
  20. }
  21. }

超时调用

日志增强

日志级别

  • NONE:默认的,不显示任何日志;
  • BASIC:仅记录请求方法、URL、响应状态码及执行时间;
  • HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息;
  • FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据。

配置日志配置的Bean

  1. import feign.Logger;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. @Configuration
  5. public class FeignConfig
  6. {
  7. @Bean
  8. Logger.Level feignLoggerLevel()
  9. {
  10. return Logger.Level.FULL;
  11. }
  12. }

然后在yml文件中同样需要对日志进行配置

  1. logging:
  2. level:
  3. # feign日志以什么级别监控哪个接口
  4. com.lun.springcloud.service.PaymentFeignService: debug