zoukankan      html  css  js  c++  java
  • 【SpringCloud】Hystrix服务降级(十)

    Hystrix介绍  

      Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。

      “断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不长时间的等待或者抛出调用方法无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

      github地址:https://github.com/Netflix/Hystrix

      服务降级  

      所谓降级,就是当某个服务出现异常之后,服务器将不再被调用,此时服务端可以自己准备一个本地的fallback回调,返回一个缺省值。 这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强,当然这也要看适合的业务场景。

      可能出现服务降级的情况:

    • 程序运行异常
    • 服务超时
    • 服务熔断出发服务降级
    • 线程池/信号量打满也会导致服务降级

    Hystrix使用

      项目准备

      搭建项目,本章采用的项目框架如下:

      

      参考:【SpringCloud】快速入门(一)

    服务降级Fallback

      1、在服务提供者模块(test-springcloud-provider-payment8008)中,引入Hystrix的依赖:

    1 <!-- hystrix -->
    2 <dependency>
    3     <groupId>org.springframework.cloud</groupId>
    4     <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    5 </dependency>

        完整pom如下:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <project xmlns="http://maven.apache.org/POM/4.0.0"
     3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     5     <parent>
     6         <artifactId>test-springcloud</artifactId>
     7         <groupId>com.test</groupId>
     8         <version>1.0-SNAPSHOT</version>
     9     </parent>
    10     <modelVersion>4.0.0</modelVersion>
    11 
    12     <artifactId>test-springcloud-provider-payment8008</artifactId>
    13 
    14     <dependencies>
    15 
    16         <!-- hystrix -->
    17         <dependency>
    18             <groupId>org.springframework.cloud</groupId>
    19             <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    20         </dependency>
    21 
    22         <!-- eureka client -->
    23         <dependency>
    24             <groupId>org.springframework.cloud</groupId>
    25             <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    26         </dependency>
    27 
    28         <!-- spring boot -->
    29         <dependency>
    30             <groupId>org.springframework.boot</groupId>
    31             <artifactId>spring-boot-starter-web</artifactId>
    32         </dependency>
    33         <dependency>
    34             <groupId>org.springframework.boot</groupId>
    35             <artifactId>spring-boot-starter-actuator</artifactId>
    36         </dependency>
    37 
    38         <dependency>
    39             <groupId>org.springframework.boot</groupId>
    40             <artifactId>spring-boot-devtools</artifactId>
    41             <scope>runtime</scope>
    42             <optional>true</optional>
    43         </dependency>
    44 
    45         <dependency>
    46             <groupId>org.projectlombok</groupId>
    47             <artifactId>lombok</artifactId>
    48             <optional>true</optional>
    49         </dependency>
    50         <dependency>
    51             <groupId>org.springframework.boot</groupId>
    52             <artifactId>spring-boot-starter-test</artifactId>
    53             <scope>test</scope>
    54         </dependency>
    55 
    56     </dependencies>
    57 
    58     <build>
    59         <finalName>test-springcloud-provider-payment8008</finalName>
    60     </build>
    61 </project>
    View Code

      2、配置文件如下:

     1 # 端口
     2 server:
     3   port: 8008
     4 
     5 spring:
     6   application:
     7     name: cloud-payment-service
     8 
     9 eureka:
    10   client:
    11     service-url:
    12       defaultZone: http://localhost:8761/eureka
    13   instance:
    14     #  instance:
    15     instance-id: ${spring.cloud.client.ip-address}:${server.port}
    16     # 访问路径可以显示IP地址
    17     prefer-ip-address: true

      3、编辑启动类,使用注解@EnableCircuitBreaker,允许断路器

    1 @SpringBootApplication
    2 @EnableEurekaClient
    3 //允许断路器
    4 @EnableCircuitBreaker
    5 public class PaymentMain8008 {
    6     public static void main(String[] args) {
    7         SpringApplication.run(PaymentMain8008.class, args);
    8     }
    9 }

      4、编辑业务类,并在方法上使用@HystrixCommand注解,表明方法支持服务降级,且设置了超时的降级策略

     1 @Service
     2 public class PaymentService {
     3 
     4     public String paymentInfo_OK(Integer id) {
     5         return "线程池:" + Thread.currentThread().getName()
     6                 + ",paymentInfo_OK,ID == " + id;
     7     }
     8 
     9 
    10     // fallbackMethod: 设置HystrixCommand服务降级所使用的方法名称,注意该方法需要与原方法定义在同一个类中,并且方法签名也要一致
    11     // commandProperties: 设置HystrixCommand属性,如:断路器失败百分比、断路器时间容器大小等
    12     // 设置断路器超时降级策略,时间3000毫秒超时
    13     @HystrixCommand(fallbackMethod = "paymentInfo_TimeoutHandler", commandProperties = {
    14             @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
    15     })
    16     public String paymentInfo_Timeout(Integer id) {
    17         int second = 5000;
    18         try {
    19             // 休眠5000毫秒
    20             TimeUnit.MILLISECONDS.sleep(second);
    21         } catch (InterruptedException e) {
    22             e.printStackTrace();
    23         }
    24         // 异常
    25 //        int n = 10/0;
    26         return "线程池:" + Thread.currentThread().getName()
    27                 + ",paymentInfo_Timeout,ID == " + id
    28                 + ",耗时" + second + "毫秒";
    29     }
    30 
    31     public String paymentInfo_TimeoutHandler(Integer id) {
    32         String result = "线程池:" + Thread.currentThread().getName()
    33                 + ",paymentInfo_TimeoutHandler,ID == " + id;
    34         return result;
    35     }
    36 }

      5、编辑controller

     1 @RestController
     2 @Slf4j
     3 public class PaymentController {
     4 
     5     @Autowired
     6     private PaymentService paymentService;
     7 
     8     @Value("${server.port}")
     9     private String serverPort;
    10 
    11     @GetMapping(value = "/payment/hystrix/ok/{id}")
    12     public String paymentInfo_OK(@PathVariable("id") Integer id) {
    13         String result = paymentService.paymentInfo_OK(id);
    14         log.info("result===" + result);
    15         return result;
    16     }
    17 
    18     @GetMapping(value = "/payment/hystrix/timeout/{id}")
    19     public String paymentInfo_Timeout(@PathVariable("id") Integer id) {
    20         String result = paymentService.paymentInfo_Timeout(id);
    21         log.info("result===" + result);
    22         return result;
    23     }
    24 
    25 }

      6、测试,启动注册中心,以及服务提供者项目

        访问地址:http://localhost:8008/payment/hystrix/ok/1,正常响应

        

        访问地址:http://localhost:8008/payment/hystrix/timeout/1,服务降级

        

        同时,可以修改业务类中paymentInfo_Timeout方法,让此方法报异常,然后进行访问,发现一样会服务降级

    全局服务降级DefaultProperties

      1、在服务消费者模块(test-springcloud-order7996)中,引入Hystrix的依赖:

        完整pom如下:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <project xmlns="http://maven.apache.org/POM/4.0.0"
     3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     5     <parent>
     6         <artifactId>test-springcloud</artifactId>
     7         <groupId>com.test</groupId>
     8         <version>1.0-SNAPSHOT</version>
     9     </parent>
    10     <modelVersion>4.0.0</modelVersion>
    11 
    12     <artifactId>test-springcloud-order7996</artifactId>
    13 
    14     <dependencies>
    15 
    16         <!-- hystrix -->
    17         <dependency>
    18             <groupId>org.springframework.cloud</groupId>
    19             <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    20         </dependency>
    21 
    22         <!-- openfeign -->
    23         <dependency>
    24             <groupId>org.springframework.cloud</groupId>
    25             <artifactId>spring-cloud-starter-openfeign</artifactId>
    26         </dependency>
    27 
    28         <!-- eureka client -->
    29         <dependency>
    30             <groupId>org.springframework.cloud</groupId>
    31             <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    32         </dependency>
    33 
    34         <!-- spring boot -->
    35         <dependency>
    36             <groupId>org.springframework.boot</groupId>
    37             <artifactId>spring-boot-starter-web</artifactId>
    38         </dependency>
    39         <dependency>
    40             <groupId>org.springframework.boot</groupId>
    41             <artifactId>spring-boot-starter-actuator</artifactId>
    42         </dependency>
    43 
    44         <dependency>
    45             <groupId>org.springframework.boot</groupId>
    46             <artifactId>spring-boot-devtools</artifactId>
    47             <scope>runtime</scope>
    48             <optional>true</optional>
    49         </dependency>
    50 
    51         <dependency>
    52             <groupId>org.projectlombok</groupId>
    53             <artifactId>lombok</artifactId>
    54             <optional>true</optional>
    55         </dependency>
    56         <dependency>
    57             <groupId>org.springframework.boot</groupId>
    58             <artifactId>spring-boot-starter-test</artifactId>
    59             <scope>test</scope>
    60         </dependency>
    61 
    62     </dependencies>
    63 
    64     <build>
    65         <finalName>test-springcloud-order7996</finalName>
    66     </build>
    67 </project>
    pom.xml

      2、编辑配置文件如下:

     1 # 端口
     2 server:
     3   port: 7996
     4 
     5 spring:
     6   application:
     7     name: cloud-order
     8 
     9 eureka:
    10   client:
    11     service-url:
    12       defaultZone: http://localhost:8761/eureka
    13   instance:
    14     #  instance:
    15     instance-id: ${spring.cloud.client.ip-address}:${server.port}
    16     # 访问路径可以显示IP地址
    17     prefer-ip-address: true

      3、编辑启动类

        使用注解@EnableFeignClients,启动openfeign

        使用注解@EnableHystrix,启用Hystrix,查看注解@EnableHystrix,里面也包含了注解@EnableCircuitBreaker

     1 @SpringBootApplication
     2 @EnableEurekaClient
     3 @EnableFeignClients
     4 // 启动Hystrix
     5 @EnableHystrix
     6 public class OrderMain7996 {
     7     public static void main(String[] args) {
     8         SpringApplication.run(OrderMain7996.class, args);
     9     }
    10 }

      4、编辑一个接口,并使用@FeignClient注解,表明一个是openfeign客户端

     1 @Component
     2 // openfeign客户端
     3 @FeignClient(value = "CLOUD-PAYMENT-SERVICE") 4 public interface PaymentHystrixService {
     5 
     6     @GetMapping(value = "/payment/hystrix/ok/{id}")
     7     public String paymentInfo_OK(@PathVariable("id") Integer id);
     8 
     9     @GetMapping(value = "/payment/hystrix/timeout/{id}")
    10     public String paymentInfo_Timeout(@PathVariable("id") Integer id);
    11 }

      5、编写一个controller,内容如下

        1)类上需要使用@DefaultProperties(defaultFallback = "paymentClobalFallbackMethod"),定义一个默认的回调方法

        2)paymentTimeout方法上需要使用@HystrixCommand 支持服务降级

     1 @RestController
     2 @Slf4j
     3 @DefaultProperties(defaultFallback = "paymentClobalFallbackMethod")
     4 public class OrderHystrixController {
     5     @Autowired
     6     private PaymentHystrixService paymentHystrixService;
     7 
     8     @GetMapping(value = "/consumer/payment/hystrix/ok/{id}")
     9     public String paymentInfo_OK(@PathVariable("id") Integer id) {
    10         String result = paymentHystrixService.paymentInfo_OK(id);
    11         log.info("result===" + result);
    12         return result;
    13     }
    14 //    @HystrixCommand(fallbackMethod = "paymentTimeoutFallbackMethod", commandProperties = {
    15 //            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
    16 //    })
    17     @GetMapping(value = "/consumer/payment/hystrix/timeout/{id}")
    18     // @HystrixCommand 支持服务降级
    19     @HystrixCommand
    20     public String paymentTimeout(@PathVariable("id") Integer id) {
    21         int n = 10/0;
    22         String result = paymentHystrixService.paymentInfo_Timeout(id);
    23         log.info("result===" + result);
    24         return result;
    25     }
    26 
    27     public String paymentTimeoutFallbackMethod(@PathVariable("id") Integer id) {
    28         String result = "消费者:对方支付系统繁忙,请稍后再试,ID == " + id;
    29         log.info("result===" + result);
    30         return result;
    31     }
    32 
    33

      6、测试

        1)启动Eureka注册中心,关闭服务提供者项目,启动服务消费者模块(test-springcloud-order7996)

        2)访问地址:http://localhost:7996/consumer/payment/hystrix/ok/1,不支持服务降级

          

        3)访问地址:http://localhost:7996/consumer/payment/hystrix/timeout/1,支持服务降级

          

    通配服务降级

      1、在以上项目的基础上,新增接口实现类PaymentFallbackService,实现接口PaymentHystrixService

     1 @Component
     2 public class PaymentFallbackService implements PaymentHystrixService {
     3     public String paymentInfo_OK(Integer id) {
     4         return "PaymentFallbackService——》paymentInfo_OK——》统一处理:" + id;
     5     }
     6 
     7     public String paymentInfo_Timeout(Integer id) {
     8         return "PaymentFallbackService——》paymentInfo_Timeout——》统一处理:" + id;
     9     }
    10 }

      2、修改接口PaymentHystrixService的配置,如下:

    1 @Component
    2 // openfeign客户端
    3 // fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,
    4 // fallback指定的类必须实现@FeignClient标记的接口
    5 @FeignClient(value = "CLOUD-PAYMENT-SERVICE", fallback = PaymentFallbackService.class)
    6 public interface PaymentHystrixService {

      3、测试

        1)启动Eureka注册中心,关闭服务提供者项目,启动服务消费者模块(test-springcloud-order7996)

        2)访问地址:http://localhost:7996/consumer/payment/hystrix/ok/1,支持服务降级,且是通配服务降级的返回内容

          

        3)访问地址:http://localhost:7996/consumer/payment/hystrix/timeout/1,支持服务降级,返回的是默认全局的服务降级内容

          

  • 相关阅读:
    剑指Offer-11.二进制中1的个数(C++/Java)
    剑指Offer-10.矩形覆盖(C++/Java)
    剑指Offer-9.变态跳台阶(C++/Java)
    UVA 1608 Non-boring sequence 不无聊的序列(分治,中途相遇)
    UVA1607 Gates 与非门电路 (二分)
    UVA 1451 Average平均值 (数形结合,斜率优化)
    UVA 1471 Defense Lines 防线 (LIS变形)
    UVA 1606 Amphiphilic Carbon Molecules 两亲性分子 (极角排序或叉积,扫描法)
    UVA 11134 FabledRooks 传说中的车 (问题分解)
    UVA 1152 4 Values Whose Sum is Zero 和为0的4个值 (中途相遇)
  • 原文地址:https://www.cnblogs.com/h--d/p/12702011.html
Copyright © 2011-2022 走看看