SpringCloud之Hystrix生死符

一、简介

  • 基本介绍

    在微服务架构中,我们将服务拆分成若干个单元,通过远程服务互相调用,如果多级节点调用过程中一个节点出现故障,就会因依赖关系形成故障蔓延,导致雪崩,为了保证系统的可用我们提出了断路器模型。Netflix开源了Hystrix组件,这在2.4.X以上版本使用的是Resilience4j(这是一款轻量级,易于使用的容错库,其灵感来自于Netflix Hystrix,但是专为Java8和函数式编程而设计)

  • 为什么断路

    1. 隔离:将请求封装在HystrixCommand中,然后这些请求在一个独立的线程中执行,每个依赖服务维护一个小的线程池(或信号量),在调用失败或超时的情况下可以断开依赖调用或者返回指定逻辑
    2. 降级:服务降级是指当请求后端服务出现异常的时候, 可以使用fallback方法返回的值
    3. 熔断:当HystrixCommand请求后端服务失败数量超过一定比例(默认50%), 断路器会切换到开路状态(Open). 这时所有请求会直接失败而不会发送到后端服务,断路器保持在开路状态一段时间后(默认5秒),自动切换到半开路状态(HALF-OPEN),这时会判断下一次请求的返回情况, 如果请求成功, 断路器切回闭路状态(CLOSED),否则重新切换到开路状态(OPEN)
    4. 仪表盘:Hystrix提供了可视化的仪表盘,对服务可用性做到实时监测的作用
  • Hystrix流程说明

    1:每次调用创建一个新的HystrixCommand,把依赖调用封装在run()方法中.
    2:执行execute()/queue做同步或异步调用.
    4:判断熔断器(circuit-breaker)是否打开,如果打开跳到步骤8,进行降级策略,如果关闭进入步骤5.
    5:判断线程池/队列/信号量是否跑满,如果跑满进入降级步骤8,否则继续后续步骤6.
    6:调用HystrixCommand的run方法.运行依赖逻辑
    6a:依赖逻辑调用超时,进入步骤8.
    7:判断逻辑是否调用成功
    7a:返回成功调用结果
    7b:调用出错,进入步骤8.
    8:计算熔断器状态,所有的运行状态(成功, 失败, 拒绝,超时)上报给熔断器,用于统计从而判断熔断器状态.
    9:getFallback()降级逻辑.以下四种情况将触发getFallback调用:
     (1):run()方法抛出非HystrixBadRequestException异常。
     (2):run()方法调用超时
     (3):熔断器开启拦截调用
     (4):线程池/队列/信号量是否跑满
    9a:没有实现getFallback的Command将直接抛出异常
    9b:fallback降级逻辑调用成功直接返回
    9c:降级逻辑调用失败抛出异常
    10:返回执行成功结果

  • 断路策略

    1. 主动断开:在客户端请求时,直接设置超时时间,超过时间直接返回,不要造成服务堆积

    2. 限流:在高并发场景下,设置最大并发数

    3. 降级:服务失败或异常后,返回指定默认信息,这个一般是在服务端处理

    4. 熔断:当错误数超过阈值时快速失败,不调用后端服务,同时隔一定时间放几个请求去重试后端服务是否能正常调用,如果成功则关闭熔断状态,失败则继续快速失败,直接返回。(此处有个重试,重试就是弹性恢复的能力)

    5. 隔离:把每个依赖或调用的服务都隔离开来,防止级联失败引起整体服务不可用

      在这里插入图片描述

二、Hystrix独立使用

  • pom依赖

    <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>
    <!--        健康监控包     -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    复制代码
  • 启动配置

    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableCircuitBreaker//开启断路器
    @EnableHystrixDashboard//开启仪表盘
    public class BikeHystrixApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(BikeHystrixApplication.class, args);
        }
    
        /**
         * 设置负载均衡
         * @return
         */
        @Bean
        @LoadBalanced
        RestTemplate restTemplate(){
    
            return new RestTemplate();
        }
    }
    复制代码
  • 测试验证

    1. 服务降级:一般是服务端的断路策略,当服务不可用时,返回一个默认值。

      @RestController
      @RequestMapping("/bike-hystrix")
      @Slf4j
      public class BikeHystrixController {
      
          @Autowired
          RestTemplate restTemplate;
      
        	//添加注解,指定回调方法
          @HystrixCommand(fallbackMethod = "fallBack")
          @GetMapping("/hystrix")
          public String hystrix(){
            	
            	//模拟服务异常,触发服务降级
            	int i=1/0;
      
              String resp = null;
              /**
               * 如果restTemplate没有设置@LoadBalanced是不能用服务名代替ip:port的方式请求,否则会报识别不了host的错误,
               * 如果配置了该注解,那么就需要使用服务名
               */
              resp = restTemplate.getForObject("http://bike-business/bike-business/hystrix", String.class);
      
              return resp;
      
          }
      
      		//当业务方法执行异常时会执行该方法,相当于是服务的降级,对于服务降级常用于服务端。当当前服务不可用时返回一个默认值
          public String fallBack(){
              return "this is hystrix err ";
          }
      
      
      }
      复制代码

      HystrixCommand注解说明

      @Target({ElementType.METHOD})
      @Retention(RetentionPolicy.RUNTIME)
      @Inherited
      @Documented
      public @interface HystrixCommand {
           // HystrixCommand 命令所属的组的名称:默认注解方法类的名称
          String groupKey() default "";
       
          // HystrixCommand 命令的key值,默认值为注解方法的名称
          String commandKey() default "";
       
          // 线程池名称,默认定义为groupKey
          String threadPoolKey() default "";
          // 定义回退方法的名称, 此方法必须和hystrix的执行方法在相同类中
          String fallbackMethod() default "";
          // 配置hystrix命令的参数
          HystrixProperty[] commandProperties() default {};
          // 配置hystrix依赖的线程池的参数
          HystrixProperty[] threadPoolProperties() default {};
       
          // 如果hystrix方法抛出的异常包括RUNTIME_EXCEPTION,则会被封装HystrixRuntimeException异常。我们也可以通过此方法定义哪些需要忽略的异常
          Class<? extends Throwable>[] ignoreExceptions() default {};
       
          // 定义执行hystrix observable的命令的模式,类型详细见ObservableExecutionMode
          ObservableExecutionMode observableExecutionMode() default ObservableExecutionMode.EAGER;
       
          // 如果hystrix方法抛出的异常包括RUNTIME_EXCEPTION,则会被封装HystrixRuntimeException异常。此方法定义需要抛出的异常
          HystrixException[] raiseHystrixExceptions() default {};
       
          // 定义回调方法:但是defaultFallback不能传入参数,返回参数和hystrix的命令兼容
          String defaultFallback() default "";
      }
      复制代码
    2. 服务熔断

      • 我们测试服务熔断需要开启多个服务节点来验证,分别开启bike-business,bike-business2两个业务系统,添加相同的接口

        @GetMapping("/hystrix")
        public String hystrix(){
            return "hystrix resp : " + port;
        }
        复制代码
      • 客户端添加hystrix超时时间,超时设置了2秒,我们在上一步bike-business2系统关闭模拟服务器宕机,那么根据ribbon的负载均衡策略,在多次轮训到bike-business2业务系统时,监测到服务器宕机,就会触发熔断机制。那么我们可以预想,当bike-business2熔断之后,结果只会返回bike-business的结果

        hystrix:
          command:
            default:
              execution:
                isolation:
                  strategy: SEMAPHORE
                  thread:
                    timeoutInMilliseconds: 2000 # 设置hystrix的超时时间为2s
        复制代码
      • 通过postman模拟请求查看日志打印信息,在多次触发了fallback之后,随后将只返回了bike-business结果

        c.b.h.controller.BikeHystrixController   : this is hystrix err 
        c.b.h.controller.BikeHystrixController   : hystrix resp : 8126
        c.b.h.controller.BikeHystrixController   : hystrix resp : 8126
        c.b.h.controller.BikeHystrixController   : hystrix resp : 8126
        c.b.h.controller.BikeHystrixController   : hystrix resp : 8126
        c.b.h.controller.BikeHystrixController   : hystrix resp : 8126
        c.b.h.controller.BikeHystrixController   : hystrix resp : 8126
        复制代码

三、openFeign的集成

  • pom依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    复制代码
  • 启动配置

    @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
    @EnableDiscoveryClient
    @EnableCircuitBreaker
    @EnableHystrixDashboard
    @EnableFeignClients//开启feign
    public class BikeHystrixApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(BikeHystrixApplication.class, args);
        }
    }
    
    复制代码
  • 配置文件

    feign:
      hystrix:
        enabled: true #开启熔断支持
    复制代码
  • 测试验证

    1. 配置feignClient

      //通过配置fallbackFactory指定服务降级的类
      @FeignClient(value = "bike-business",fallbackFactory = FallbackFactory.class)
      public interface BikeHystrixFeignClient {
      
          @GetMapping("/bike-business/hystrix")
          String hystrix();
      }
      复制代码
    2. 服务降级实现

      /**
       * 实现FallbackFactory接口
       */
      @Component
      @Slf4j
      public class FallbackFactory implements feign.hystrix.FallbackFactory<BikeHystrixFeignClient> {
      
          @Override
          public BikeHystrixFeignClient create(Throwable throwable) {
              log.error(throwable.getMessage());
            	//通过匿名内部类来自定义异常情况的返回数据
              return new BikeHystrixFeignClient(){
                  @Override
                  public String hystrix() {
                      return throwable.getMessage();
                  }
              };
          }
      }
      复制代码
    3. 测试验证

      在controller新增feign调用接口,在验证的过程中,如果bike-business服务有一个节点停掉,那么feign就会进行单节点熔断,当服务重启时,服务又会自动分发到重启的节点,当所有bike-business节点服务都不可用时,触发FallbackFactory的实现。

四、仪表盘

  • pom依赖

    <!-- 新增仪表盘依赖 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
    </dependency>
    复制代码
  • 启动配置

    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableCircuitBreaker//开启断路器
    @EnableHystrixDashboard//开启仪表盘
    public class BikeHystrixApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(BikeHystrixApplication.class, args);
        }
    
        /**
         * 设置负载均衡
         * @return
         */
        @Bean
        @LoadBalanced
        RestTemplate restTemplate(){
    
            return new RestTemplate();
        }
    }
    复制代码
  • 配置文件

    hystrix:
      command:
        default:
          execution:
            timeout:
              #是否开启超时熔断
              enabled: true
            isolation:
            	#hystrix隔离策略
            	#SEMAPHORE - 它在调用线程上执行,并发请求受信号量计数的限制(Zuul默认此策略)
    					#THREAD - 它在一个单独的线程上执行,并发请求受到线程池中线程数的限制
              strategy: SEMAPHORE #如果仪表盘的Thread Pools一直处于loading状态,那么可设置为Therad隔离策略
              thread:
                timeoutInMilliseconds: 2000 # 设置hystrix的超时时间为2s
      #添加本地代理列表
      dashboard:
        proxy-stream-allow-list: "localhost"
    
    #暴露全部的监控信息
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    复制代码
  • 测试验证

    1. 启动项目,访问http://localhost:8128/hystrix

    image-20210706135354690.png

    • Deplay 该参数用来控制服务器上轮询监控信息的延迟时间,默认是2000毫秒,可以通过配置该属性来降低客户端的网络和cpu消耗。
    • Title该参数对应了头部标题Hystrix Stream之后的内容,默认会使用哦具体监控实例的URL,可疑通过配置该信息来展示更合适的标题。
    1. 根据Hystrix Dashboard提示填写具体监测的服务,比如单节点Single Hystrix App填写https://hystrix-app:port/actuator/hystrix.stream

    2. 查看监控参数

      image-20210706140758778.png

      • 实心圆:共有两种含义。它通过颜色的变化代表了实例的健康程度,它的健康程度从 绿色 > 黄色 > 橙色 > 红色 递减;它的大小也会根据实例的请求流量发生变化,流量越大实心圆就越大,所以通过该实心圆的展示,就可以在大量实例中快速的发现故障实例和高压力实例
      • 百分数:最近10s错误百分比
      • circuit:断路状态
    3. 模拟熔断

      • 停掉远程服务bike-business所有节点,再通过feign频繁请求远程服务,观察仪表盘的状态变化

        image-20210706142041720.png

      • postman返回请求信息为Hystrix circuit short-circuited and is OPEN。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享