SpringCloud之Hystrix服务的降级和熔断

  |   0 评论   |   0 浏览

Hystrix是什么

Hystrix是一个用于处理分布式系统的延迟和容错的一个开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,

Hystrix能保证在一个依赖出现问题的情况下, 不会导致整体服务失败,避免级联故障,以提高分布式系统的稳定性。当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的,可处理的备选响应 ,而不是长时间等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

如何理解服务熔断和服务降级

答:服务熔断和服务降级是在分布式系统中应对高并发或者故障的两种常见策略。

服务熔断是一种保护系统的策略,用于防止服务雪崩效应的出现 。如果一个服务发生故障或者网络延迟过高,就会导致该服务的请求被阻塞。如果这种情况发生在大量服务上,整个系统就会瘫痪,出现服务雪崩效应。服务熔断的作用就是在发生这种情况时,及时将受影响的服务切断,避免其对整个系统的影响,让其快速恢复正常状态。

服务降级则是一种为了保证核心功能的策略,它通过降低服务质量或者停止某些非核心功能来保证系统的可用性 。在高并发的情况下,系统可能无法承受所有请求,如果一些非核心功能的请求过多,就会影响系统的核心功能。这时候可以通过服务降级的方式来降低对非核心功能的支持,从而保证系统的核心功能的正常运行。例如,可以暂停某些低优先级的服务,减少服务响应时间,或者通过简化页面或者减少数据量来缓解系统的压力。

总之,服务熔断和服务降级都是为了保障系统的可用性和稳定性,它们可以根据系统的实际情况来灵活运用。

Hysrix的主要功能

引包: compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-netflix-hystrix

当服务的提供方出现问题时,通过hystrix可以让服务的使用方进行容错处理,避免错误在整个服务链条中蔓延。

如果要使用Hystrix,需要在feign配置中启用它:feign.hystrix.enabled = true

降级: 调用服务失败时, 可以使用fallback方法返回一个托底数据(这就是我们优化),也就是常见于服务宕机时,服务端能自动返回一个友好的提示,告知用户当前服务暂不可用。

具体的代码实现,则可以为每一个接口提供一个fallback方法,或者全局提供一个通用的fallback方法用于返回错误信息或用户提示。

熔断: 当调用失败达到某种设定好的阈值时,如一分钟内有70%的请求失败,便不再请求服务提供者的接口,直接返回托底数据(我们设置的备选方案),处在熔断状态时,则每次请求都直接返回托底数据,不再向服务提供者发请求

半熔断: 半熔断是一种恢复机制,在熔断了一定的时间后,会再将请求发往服务提供方,如果收到成功响应,则关闭熔断

隔离策略: 当我们使用了Hystrix时,Hystrix将所有的外部调用都封装成一个HystrixCommand或者HystrixObservableCommand对象,这些外部调用将会在一个独立的线程中运行。我们可以将出现问题的服务通过熔断、降级等手段隔离开来,这样不影响整个系统的主业务。

熔断与降级的实现区别:

熔断是写在服务提供者里面的,降级是写在服务调用者里面的

服务降级

原理 :常见于服务宕机或服务器关闭时,客户端能自动返回一个友好的提示,告知用户当前服务暂不可用。客户端通过使用fallback方法返回一个托底默认值数据(友好的提示)

实现原理 :降级是写在服务调用者里面的

  • 1.引入对应的依赖
  • 2.在配置文件里面配置降级许可:feign配置中启用它:feign.hystrix.enabled = true
  • 3.创建一个降级配置类,实现FallbackFactory这个接口,和实现这个接口的create方法,
  • 4.然后在create方法里面对需要降级的方法进行优化处理(友好的提示还是其他怎么的 )
  • 5.在需要降级的接口上面,添加@FeignClient(value = "springcloud服务名称",fallbackFactory = 需要降级的配置类.class)

1.引入对应的依赖

 <!--Ribbon-->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-ribbon</artifactId>
     <version>1.4.6.RELEASE</version>
 </dependency>
 <!--Eureka依赖-->
 <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-eureka</artifactId>
     <version>1.4.6.RELEASE</version>
 </dependency>
 <!--使用hystrix,一定要导入hystrix依赖和feign依赖,因为hystrix是官方默认绑定使用feign的-->
 <!--hystrix依赖-->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-hystrix</artifactId>
     <version>1.4.6.RELEASE</version>
 </dependency>
 <!--feign-->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-feign</artifactId>
     <version>1.4.6.RELEASE</version>
 </dependency>

2.在配置文件里面配置降级许可:feign配置中启用它:feign.hystrix.enabled = true

开启降级后,服务降级是自动触发的。

 
 feign:
   hystrix:
     enabled: true   #开启降级
     # application.yml
     command:
        default:
          execution:
            isolation:
              thread:
                timeoutInMilliseconds: 10000 # 设置超时时间为10秒
 

实现降级配置类

3.创建一个降级配置类,实现FallbackFactory这个接口,和实现这个接口的create方法,

4.然后在create方法里面对需要降级的方法进行优化处理(友好的提示还是其他怎么的 )

 /**
  * 服务降级演示类
  * 降级方法:对需要降级的接口 实现一个FallbackFactory工厂实现类
  */
 @Component
 public class TestFeignFallBackFactory implements FallbackFactory<TestFeignService> {
 
     private static final Logger log = LoggerFactory.getLogger(TestFeignService.class);
 
     /**
      * 需要对这个接口方法进行降级
      * 降级方法:在降级方法去实现create方法,在create方法里面去实现需要降级的接口的自有方法
      * 原理就是客户端面临服务器关闭时,提前准备的默认提示
      * @param cause
      * @return
      */
     @Override
     public TestFeignService create(Throwable cause) {
         /**
          * 去实现这个接口,可以真的这些接口,进行自身的合理化优化,从而达到降低服务压力的需要
          */
         return new TestFeignService() {
             @Override
             public RestTemplateEntity get(String id) {
                 RestTemplateEntity restTemplateEntity = new RestTemplateEntity();
                 restTemplateEntity.setId(id);
                 restTemplateEntity.setTestName("这个id=>"+id+",没有对应的信息,null---@现在进行服务降级~");
                 return restTemplateEntity;
             }
 
             @Override
             public RestTemplateEntity post(RestTemplateEntity restTemplateEntity) {
                 restTemplateEntity.setId(restTemplateEntity.getId());
                 restTemplateEntity.setTestName("这个id=>"+restTemplateEntity.getId()+",没有对应的信息,null---@现在进行服务降级~");
                 return restTemplateEntity;
             }
         };
     }
 }

5.在需要降级的接口上面,添加@FeignClient(value = "springcloud服务名称",fallbackFactory = 需要降级的配置类.class)

 /**
  * feign 以接口的形式定义与调用远程服务
  * 演示服务降级:Hystrix服务降级 ~
  */
 
 /**
  * 实现服务降级的方法:
  * 原理:当常见于服务宕机时,服务端能自动返回一个友好的提示,告知用户当前服务暂不可用。
  * 实现:
  *  1.引入对应的依赖
  *  2.在配置文件里面配置降级许可
  *  3.创建一个降级配置类,实现FallbackFactory这个接口,和实现这个接口的create方法,
  *  4.然后在create方法里面对需要降级的方法进行优化处理
  *  5.在需要降级的接口上面,添加@FeignClient(value = "springcloud服务名称",fallbackFactory = 需要降级的配置类.class)
  */
 @Component //注册到spring容器中
 /**
  * @FeignClient:微服务客户端注解,value:指定微服务的名字,这样就可以使Feign客户端直接找到对应的微服务
  * 当常见于服务宕机时,服务端能自动返回一个友好的提示,告知用户当前服务暂不可用。
  * 代码实现:则可以为每一个接口提供一个fallback(最好声明一个降级配置类同一处理)方法,或者全局提供一个通用的fallback方法用于返回错误信息或用户提示
  */
 @FeignClient(value = "HWTOOL-MANAGE-SERVICE",fallbackFactory = TestFeignFallBackFactory.class)//fallbackFactory指定降级配置类
 public interface TestFeignService {
 
     /**
      * 远程调用get请求示例
      * @param id
      * @return
      */
     @GetMapping("/restTemplate/get/{id}")
     public RestTemplateEntity get(@PathVariable("id") String id);
 
 
     /**
      * 远程调用post请求
      * @param restTemplateEntity
      * @return
      */
     @PostMapping("/restTemplate/post")
     public RestTemplateEntity post(RestTemplateEntity restTemplateEntity);
 }

服务熔断

原理 : 当调用失败达到某种设定好的阈值时 ,如一分钟内有70%的请求失败, 便不再请求服务提供者的接口,直接返回托底数据(我们设置的备选方案) ,处在熔断状态时,则每次请求都直接返回托底数据,不再向服务提供者发请求

实现原理

  • 引入依赖
  • 配置注册中心信息
  • 新增一个熔断的备选方案也可以为提示
  • 接口引入熔断的备选方案
  • 主启动类添加熔断注解

引入依赖

 <!--导入Hystrix依赖-->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-hystrix</artifactId>
     <version>1.4.6.RELEASE</version>
 </dependency>

配置注册中心信息

 # Eureka配置:配置服务注册中心地址(将这个模块服务注册到注册中心上面)
 eureka:
   client:
     service-url:
       # 注册中心地址7001-7003
       defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
       instance:
         instance-id: hwTool-hystrix-8006 #修改Eureka上的默认描述信息
         prefer-ip-address: true #改为true后默认显示的是ip地址而不再是localhost
         #service-url:
         #defaultZone: http://localhost:7001/eureka/
         #instance:
         #instance-id: hwTool-manage-service   #修改eureka上面的默认描述信息
         #application.yml
         hystrix:
           command:
             default:
               circuitBreaker:
                 requestVolumeThreshold: 10   #熔断器统计请求的阈值,默认值为 20。这个参数定义了在一个统计窗口期内,必须满足最小请求数量才能触发熔断器的打开
                 sleepWindowInMilliseconds: 5000 #熔断器打开后的等待时间,默认值为 5000 毫秒。超过时间就会打开,当熔断器打开后,在指定的等待时间内,所有请求都会直接失败,而不会发送到依赖的服务
                 errorThresholdPercentage: 60  #熔断器打开的错误率阈值,默认值为50%。当请求的错误率超过了这个阈值,熔断器将会被打开

新增一个熔断的备选方案也可以为提示

 /**
      * 根据id查询备选方案(熔断)
      * 熔断之后的备选方法
      * @param id
      * @return
      */
     public RestTemplateEntity hystrixGet(@PathVariable String id){
         RestTemplateEntity restTemplateEntity = new RestTemplateEntity();
         restTemplateEntity.setId(id);
         restTemplateEntity.setTestName("这个id=>"+id+",没有对应的信息,null---@Hystrix~");
         return restTemplateEntity;
     }

在需要进行服务熔断的方法上添加@HystrixCommand注解,并指定熔断方法和配置选项,例如: 在下面的例子中,当调用get方法时,如果该方法的调用失败次数超过一定阈值,就会打开熔断器,并执行hystrixGet方法来进行熔断处理。

接口引入熔断的备选方案

 /**
      * 服务提供者提供远程调用的get接口
      * 要是get这个是方法多次报错,就是触发熔断机制,fallbackMethod返回调用备用的熔断方法 hystrixGet
      * @param
      * @return
      */
     @GetMapping("/get/{id}")
     @HystrixCommand(fallbackMethod = "hystrixGet", commandProperties = {
     @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), // 触发熔断的最小请求数量
     @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000"), // 熔断器打开后等待的时间 
     @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60") // 触发熔断的错误百分比阈值
     })
     public RestTemplateEntity get(@PathVariable String id){
         RestTemplateEntity restTemplateEntity = testService.restTemplateGet(id);
         if (restTemplateEntity ==null){
             throw new RuntimeException("这个id=>"+id+",不存在该用户,或信息无法找到~");
         }
         return restTemplateEntity;
     }

主启动类添加熔断注解

 @EnableDiscoveryClient // Hystrix服务发现~
 @EnableCircuitBreaker // 添加对Hystrix熔断的支持注解
 @SpringBootApplication
 @EnableEurekaClient  // @EnableEurekaClient 开启Eureka客户端注解,在服务启动后自动向注册中心注册服务
 @EnableDiscoveryClient // Hystrix服务发现~
 @EnableCircuitBreaker // 添加对Hystrix熔断的支持注解
 public class HystrixApplication {
 
     public static void main(String[] args) {
         SpringApplication.run(HystrixApplication.class, args);
         System.out.println("==============服务提供者 测试熔断功能 start successfuly================");
         printEnd();
     }
 
     private static void printEnd() {
         System.out.println(" * ━━━━━━神兽出没━━━━━━ \n" +
                 " *    ┏┓   ┏┓ \n" +
                 " *   ┏┛┻━━━┛┻┓ \n" +
                 " *   ┃       ┃ \n" +
                 " *   ┃   ━   ┃ \n" +
                 " *   ┃ ┳┛ ┗┳ ┃ \n" +
                 " *   ┃       ┃ \n" +
                 " *   ┃   ┻   ┃ \n" +
                 " *   ┃       ┃ \n" +
                 " *   ┗━┓   ┏━┛Code is far away from bug with the animal protecting \n" +
                 " *     ┃   ┃    神兽保佑,代码无bug \n" +
                 " *     ┃   ┃ \n" +
                 " *     ┃   ┗━━━┓ \n" +
                 " *     ┃       ┣┓ \n" +
                 " *     ┃       ┏┛ \n" +
                 " *     ┗┓┓┏━┳┓┏┛ \n" +
                 " *      ┃┫┫ ┃┫┫ \n" +
                 " *      ┗┻┛ ┗┻┛");
     }
 }

流量监控

新增一个模块

添加依赖

 <!--Hystrix依赖-->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-hystrix</artifactId>
     <version>1.4.6.RELEASE</version>
 </dependency>
 <!--dashboard依赖-->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
     <version>1.4.6.RELEASE</version>
 </dependency>
 <!--Ribbon-->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-ribbon</artifactId>
     <version>1.4.6.RELEASE</version>
 </dependency>
 <!--Eureka-->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-eureka</artifactId>
     <version>1.4.6.RELEASE</version>
 </dependency>
 <!--实体类+web-->
 <dependency>
     <groupId>com.haust</groupId>
     <artifactId>springcloud-api</artifactId>
     <version>1.0-SNAPSHOT</version>
 </dependency>
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <!--热部署-->
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-devtools</artifactId>
 </dependency>

给主启动类添加相关注解

@EnableHystrixDashboard 开启Dashboard流量监控

 @SpringBootApplication
 // 开启Dashboard
 @EnableHystrixDashboard //开启Dashboard流量监控
 public class DeptConsumerDashboard_9001 {
     public static void main(String[] args) {
         SpringApplication.run(DeptConsumerDashboard_9001.class,args);
     }
 }

给服务端提供者添加监控依赖

 <!--        完善监控发现信息依赖-->
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-actuator</artifactId>
         </dependency>

给服务端提供者启动类添加监控页面代码

 @SpringBootApplication
 @EnableEurekaClient //EnableEurekaClient 客户端的启动类,在服务启动后自动向注册中心注册服务
 public class DeptProvider_8001 {
     public static void main(String[] args) {
         SpringApplication.run(DeptProvider_8001.class,args);
     }
   
   
     //增加一个 Servlet  添加相应的监控页面代码
     @Bean
     public ServletRegistrationBean hystrixMetricsStreamServlet(){
         ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
         //访问该页面就是监控页面
         registrationBean.addUrlMappings("/actuator/hystrix.stream");
         return registrationBean;
     }
 }

同时服务提供者端也需要导入相应的hystrix依赖

 <!--Hystrix依赖-->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-hystrix</artifactId>
     <version>1.4.6.RELEASE</version>
 </dependency>

监控页面访问

本地启动相应的流量监控模块

1.使用localhost:监控模块的端口号/hystrix 就可以访问到流量监控网址(有一个豪猪的页面)

 http://localhost:监控模块的端口号/hystrix

2.将需要监控的页面地址输入到豪猪页面下面的地址框

原文https://zhuanlan.zhihu.com/p/612505189


标题:SpringCloud之Hystrix服务的降级和熔断
作者:michael
地址:https://blog.junxworks.cn/articles/2024/01/17/1705468436011.html