SpringCloud入门组件品尝

发布时间 2023-10-04 18:03:21作者: 沈自在。

SpringCloud

1 Feign组件

1.1 基本使用

  1. 依赖
<!--springcloud整合的openFeign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  1. 开启Feign
@SpringBootApplication
@EnableEurekaClient
// 下面是关键注解
@EnableFeignClients
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class,args);
    }
}
  1. 编写feign接口
@FeignClient(name = "product-service")
public interface ProductFeignClient {

    @GetMapping(value = "/product/{id}")
    Product findById(@PathVariable("id") Long id);
}
  1. 远程调用
Product product = productFeignClient.findById(id);

1.2 Feign配置

feign:
    client:
        config:
            feignName: ##定义FeginClient的名称
                connectTimeout: 5000 # 相当于Request.Options
                readTimeout: 5000 # 相当于Request.Options
                # 配置Feign的日志级别,相当于代码配置方式中的Logger
                loggerLevel: full
                # Feign的错误解码器,相当于代码配置方式中的ErrorDecoder
                errorDecoder: com.example.SimpleErrorDecoder
                # 配置重试,相当于代码配置方式中的Retryer
                retryer: com.example.SimpleRetryer
                # 配置拦截器,相当于代码配置方式中的RequestInterceptor
                requestInterceptors:
                    - com.example.FooRequestInterceptor
                    - com.example.BarRequestInterceptor
                decode404: false
  • feignName:FeginClient的名称
  • connectTimeout : 建立链接的超时时长
  • readTimeout : 读取超时时长
  • loggerLevel: Fegin的日志级别
  • errorDecoder :Feign的错误解码器
  • retryer : 配置重试
  • requestInterceptors : 添加请求拦截器
  • decode404 : 配置熔断不处理404异常

1.3 Feign与Ribbon区别

Ribbon是一个客户端的负载均衡器,Feign是在Ribbon的基础上进行了封装

1.4 日志打印

feign:
 client:
   config:
     service-product:
       loggerLevel: FULL
logging:
 level:
   cn.itcast.order.fegin.ProductFeginClient: debug
image-20220611005635258

2 高并发问题

​ 传统Web服务的线程都是由tomcat统一管理的,这样其实会产生一个巨大的并发故障。

image-20220612170053906

比如这种情况,突然某个接口的访问量占满了线程池,那么这样同时会导致整个服务体系瘫痪,所以我们为此提出了俩种解决方案:

  1. 线程隔离
image-20220612170312216

每个接口独立线程池,即使某个接口遇到了流量洪水,其他接口一样可以正常访问。

  1. 服务限流

当某个服务达到访问阈值后直接进行报错,限流操作可以使用Redis嵌Lua脚本进行实现。

  1. 熔断降级

当下游服务器因为访问压力过大而响应变慢或失败时,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用,这种牺牲局部,保全整体的措施就叫熔断

3 熔断配置

3.1 RestTemplate

  1. 导入依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
  1. 激活
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class OrderApplicationRest {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplicationRest.class,args);
    }
}
  1. 配置降级策略
   @GetMapping("/buy/{id}")
   @HystrixCommand(fallbackMethod = "orderFallBack")
   public Product buy(@PathVariable("id") Long id){

       Product product = restTemplate.getForObject("http://product-service/product/1", Product.class);

       return product;
   }


   public Product orderFallBack(Long id){
       System.out.println("id:  "+ id  );
       Product product = new Product();
       product.setProductName("熔断降级触发");
       return product;
   }

上面的配置实现了一个简单的熔断反馈方法处理,这种处理在于可以接受参数进行细节处理,但是Hystrix提供了一个全局的熔断降级方案。

@RestController
@RequestMapping("/order")
@DefaultProperties(defaultFallback = "orderFallBack")
public class OrderController {
    
    private RestTemplate restTemplate;

    @Autowired
    public OrderController(RestTemplate restTemplate){
        this.restTemplate = restTemplate;
    }

    @GetMapping("/buy/{id}")
    @HystrixCommand
    public Product buy(@PathVariable("id") Long id){
        Product product = restTemplate.getForObject("http://product-service/product/1", Product.class);
        return product;
    }
    
    public Product orderFallBack(){
        Product product = new Product();
        product.setProductName("统一熔断降级触发");
        return product;
    }

}
  1. 设置熔断时间阈值
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000 # 设置hystrix的超时时间为5000ms

3.2 Feign

  1. 引入依赖

开个玩笑,不需要,Feign已经继承了Hystrix

  1. 实现方法

这里的实现方法其实就是实现了熔断降级方法

@Component
public class ProductFeignClientFallBack implements ProductFeignClient{
    @Override
    public Product findById(Long id) {
        Product product = new Product();
        product.setProductName("触发熔断措施");
        return product;
    }
}
  1. 配置熔断类
@FeignClient(name = "product-service",fallback = ProductFeignClientFallBack.class)
public interface ProductFeignClient {

    @GetMapping(value = "/product/{id}")
    Product findById(@PathVariable("id") Long id);
}

3.3 监控

3.3.1 dashboard

  1. 引入依赖
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
  1. 暴露端口
management:
  endpoints:
    web:
      exposure:
        include: '*'
  1. 访问Web
http://localhost:9002/actuator/hystrix.stream
image-20220614124644480

监控结果如图:

image-20220614124719437

3.3.2 Turbine

在微服务架构体系中,每个服务都需要配置Hystrix DashBoard监控。如果每次只能查看单个实例的监控数据,就需要不断切换监控地址,这显然很不方便。要想看这个系统的Hystrix Dashboard数据就需要用到Hystrix Turbine。Turbine是一个聚合Hystrix 监控数据的工具,他可以将所有相关微服务的Hystrix 监控数据聚合到一起,方便使用。

建议独立工程

  1. 引入依赖
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-turbine</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
  1. 开启服务
@SpringBootApplication
@EnableHystrix
@EnableHystrixDashboard
public class TurbineServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(TurbineServerApplication.class,args);
    }
}

  1. 服务配置
server:
  port: 8031

spring:
  application:
    name: turbine-server

eureka:
  client:
    service-url:
      defaultZone: http://localhost:9000/eureka

  instance:
    prefer-ip-address: true

turbine:
  app-config: order-service
  cluster-name-expression: "'default'"
  1. 数据监控

​ 本方法与 3.3.1 操作类似,所以不再赘述

3.4 断路器

  1. Closed:关闭状态(断路器关闭),所有请求都正常访问。代理类维护了最近调用失败的次数,如果某次调用失败,则使失败次数加1 如果最近失败次数超过了在给定时间内允许失败的阈值,则代理类切换到断开(Open)状态。此时代理开启了一个超时时钟,当该时钟超过了该时间,则切换到半断开(Half-Open)状态。该超时时间的设定是给了系统一次机会来修正导致调用失败的错误。

  2. Open:打开状态(断路器打开),所有请求都会被降级。Hystix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全关闭。默认失败比例的阈值是50%,请求次数最少不低于20次。

  3. Half Open:半开状态,open状态不是永久的,打开后会进入休眠时间(默认是5S)。随后断路器会自动进入半开状态。此时会释放1次请求通过,若这个请求是健康的,则会关闭断路器,否则继续保持打开,再次进行5秒休眠计时。

环境准备:

  1. 在订单系统中加入逻辑:

判断请求的id:

如果id=1 :正常执行(正常调用微服务)

否则 :抛出异常

2.默认Hystrix中有触发断路器状态转换的阈值

触发熔断的最小请求次数:20

触发熔断的最小失败比率:50%

熔断器开启的时长:5s

3.4.1 配置熔断策略

circuitBreaker.requestVolumeThreshold=5 
circuitBreaker.sleepWindowInMilliseconds=10000 
circuitBreaker.errorThresholdPercentage=50

解读:

  • requestVolumeThreshold:触发熔断的最小请求次数,默认20

  • errorThresholdPercentage:触发熔断的失败请求最小占比,默认50%

  • sleepWindowInMilliseconds:熔断多少秒后去尝试请求

3.4.2 隔离策略

​ 微服务使用Hystrix熔断器实现了服务的自动降级,让微服务具备自我保护的能力,提升了系统的稳定性,也较好的解决雪崩效应。其使用方式目前支持两种策略:

线程池隔离策略:使用一个线程池来存储当前的请求,线程池对请求作处理,设置任务返回处理超时时间,堆积的请求堆积入线程池队列。这种方式需要为每个依赖的服务申请线程池,有一定的资源消耗,好处是可以应对突发流量(流量洪峰来临时,处理不完可将数据存储到线程池队里慢慢处理)

信号量隔离策略:使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,请求来先判断计数器的数值,若超过设置的最大线程个数则丢弃改类型的新请求,若不超过则执行计数操作请求来计数器+1,请求返回计数器-1。这种方式是严格的控制线程且立即返回模式,无法应对突发流量(流量洪峰来临时,处理的线程超过数量,其他的请求会直接返回,不继续去请求依赖的服务)

image-20220614131323310
  • hystrix.command.default.execution.isolation.strategy : 配置隔离策略
    ExecutionIsolationStrategy.SEMAPHORE 信号量隔离
    ExecutionIsolationStrategy.4.THREAD 线程池隔离
  • hystrix.command.default.execution.isolation.maxConcurrentRequests : 最大信号量上限

4 用Sentinel替换Hystrix