SpringCloud中的Hystrix概述

服务雪崩

多个微服务之间调用的时候,A调用微服务B和微服务C,微服务B和微服务C调用了其他的微服务,这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应的时间过长或者不可用,对微服务A的调用会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”。

什么是Hystrix?

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

Hystrix可以用来干嘛?

  • 服务降级
  • 依赖隔离
  • 服务熔断

官网地址:https://github.com/Netflix/Hystrix/wiki/How-To-Use

什么是服务降级?

降级机制时应对雪崩效应的一种微服务链路保护机制

当链路的某个微服务不可用或者响应时间太长,会进行服务的降级,进而降级微服务的调用,快速返回“错误”的信息。

优先核心服务,非核心服务不可用或者弱化

通过HystrixCommand注解指定

FallbackMethod(回退函数)中具体实现降级逻辑

  • 案例:在pom文件中导入坐标
     1  <dependencies>
     2         <dependency>
     3             <groupId>junit</groupId>
     4             <artifactId>junit</artifactId>
     5         </dependency>
     6         <dependency>
     7             <groupId>mysql</groupId>
     8             <artifactId>mysql-connector-java</artifactId>
     9         </dependency>
    10         <dependency>
    11             <groupId>com.alibaba</groupId>
    12             <artifactId>druid</artifactId>
    13         </dependency>
    14         <dependency>
    15             <groupId>ch.qos.logback</groupId>
    16             <artifactId>logback-core</artifactId>
    17         </dependency>
    18         <dependency>
    19             <groupId>org.mybatis.spring.boot</groupId>
    20             <artifactId>mybatis-spring-boot-starter</artifactId>
    21         </dependency>
    22 
    23         <dependency>
    24             <groupId>org.springframework.boot</groupId>
    25             <artifactId>spring-boot-starter-web</artifactId>
    26         </dependency>
    27         <dependency>
    28             <groupId>org.springframework.boot</groupId>
    29             <artifactId>spring-boot-starter-test</artifactId>
    30         </dependency>
    31 
    32         <!-- 修改后立即生效,热部署 -->
    33         <!-- https://mvnrepository.com/artifact/org.springframework/springloaded -->
    34         <dependency>
    35             <groupId>org.springframework</groupId>
    36             <artifactId>springloaded</artifactId>
    37             <version>1.2.8.RELEASE</version>
    38         </dependency>
    39 
    40         <dependency>
    41             <groupId>org.springframework.boot</groupId>
    42             <artifactId>spring-boot-devtools</artifactId>
    43         </dependency>
    44         <dependency>
    45             <groupId>zh.stu.springcloud</groupId>
    46             <artifactId>zhservicecloud-common</artifactId>
    47             <version>1.0-SNAPSHOT</version>
    48         </dependency>
    49         <!--将微服务provider注册到eureka-->
    50         <dependency>
    51             <groupId>org.springframework.cloud</groupId>
    52             <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    53         </dependency>
    54         <dependency>
    55             <groupId>org.springframework.cloud</groupId>
    56             <artifactId>spring-cloud-starter-config</artifactId>
    57         </dependency>
    58         <!--监控完善信息-->
    59         <dependency>
    60             <groupId>org.springframework.boot</groupId>
    61             <artifactId>spring-boot-starter-actuator</artifactId>
    62         </dependency>
    63         <dependency>
    64             <groupId>org.springframework.cloud</groupId>
    65             <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    66         </dependency>67 
    68     </dependencies>
  • 在yml的文件中添加配置                      
     1 server:
     2   port: 8001
     3 mybatis:
     4   config-location: classpath:mybatis/mybatis.cfg.xml    #mybatis配置文件所在路径
     5   type-aliases-package: com.zjx.springcloud.entity      #所有Entity别名类所在包
     6   mapper-locations:
     7    - classpath:mybatis/mapper/**/*.xml                   #mapper映射文件
     8 spring:
     9   application:
    10     name: txservicecloud-dep
    11   datasource:
    12     type: com.alibaba.druid.pool.DruidDataSource        #当前数据源操作类型
    13     driver-class-name: org.gjt.mm.mysql.Driver          #mysql驱动包
    14     url: jdbc:mysql://localhost:3306/cloudDB01          #数据库名称
    15     username: root
    16     password: root
    17     dbcp2:
    18       min-idle: 5                                       #数据库连接池的最小维持连接数
    19       initial-size: 5                                   #初始化连接数
    20       max-total: 5                                      #最大连接数
    21       max-wait-millis: 200                              #等待连接获取的最大超时时间
    22 
    23 eureka:
    24   client: #客户端注册进eureka服务列表内
    25     service-url:
    26       defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
    27       #defaultZone: http://localhost:7001/eureka
    28   instance:
    29     instance-id: txservicecloud-dep-hystrix-8001  #这个就是我用来做测试的模块的名字
    30     prefer-ip-address: true
    31 info:
    32   app.name: txservicecloud-dep
    33   company.name: www.txjava.cn
    34   build.artifactId: @project.artifactId@
    35   build.version: @project.version@
  • 可以编写一个查询数据库的一个案例,分不同的层,dao层,service....以及实现接口和xml文件。此处省略。直接在控制器中去模拟场景
  • 例如在DeptController中模拟超时异常
     1    /**
     2      * @HystrixCommand  在注解中有一个
     3      * fallbackMethod  :在这个调用这个方法发生错误的时候会出发fallbackMethod中的方法,达到一个降级的效果。
     4      *
     5      *
     6      * commandProperties : 是一个数组的形式,比如在里面可以配置超时的属性
     7      * 里面的name的属性,可以在HysrixConmmandProperties.class文件中查找
     8      * @param id
     9      * @return
    10      */
    11 
    12     @HystrixCommand(fallbackMethod = "HystrixProcess",
    13     commandProperties = {
    14             @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000")
    15     })
    16     @RequestMapping(value = "/dept/get/{id}",method = RequestMethod.GET)
    17     public Dept dept (@PathVariable("id") Long id){
    18         try {
    19 //            这个方法表示,在线程休眠时间大于一秒的时候,该方法上的注解:@HystrixCommand会调用方法HystrixProcess中的提示信息。
    20             Thread.sleep(2000);
    21         } catch (InterruptedException e) {
    22             e.printStackTrace();
    23         }
    24         return deptService.findById(id);
    25     }

    因为在注解@HystrixCommand(fallbackMethod = "HystrixProcess",中调用HystrixProcess的方法,所以在添加一个HystrixProcess的方法。

     1 /**
     2      * 降级的服务的方法和返回值要和服务方法的方法一致
     3      * @param id
     4      * @return
     5      */
     6     public Dept HystrixProcess(@PathVariable("id") Long id){
     7         Dept dept=new Dept();
     8         dept.setDeptno(id);
     9         dept.setDname("该ID"+id+"没有对应的信息,null--@HystrixCommand");
    10         dept.setDb_source("访问超时");
    11         return dept;
    12 
    13     }

    这样在方法  dept   的这个方法的时候就会进入到   HystrixProcess   的这个方法中,提示异常的信息。

  • 服务的超时我们也可以使用配置的方式来使用,在服务端的yml文件中

    1 hystrix:
    2   command:
    3     default:
    4        execution:
    5           isolation:
    6             thread :
    7               timeoutInMilliseconds: 1000

注意:服务的降级方法的返回值和参数要和服务接口方法一致,默认降级方法可以设置参数列表为空。

@DefaultProperties(defaultFallback = "hystrixFallBack")可以通过@DefaultProperties来指定一个默认的服务降级方法,如果方法返回值统一(本例子统一了返回值的接口为String,默认的回退方法没有参数)则可以给多个服务接口来做服务降级。服务端的接口返回值修改,注意:服务消费端返回值也要修改成String。

服务熔断

什么是服务熔断?

当链路的某个微服务不可用或者响应时间太长,会进行服务的降级,进而熔断微服务的调用,快速返回"错误"的响应信息.当检测到该节点微服务调用响应正常后恢复调用链路.在SpringCloud框架里熔断机制通过Hystrix实现.Hystrix会监控微服务调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制.熔断机制的注解是@HystrixCommand.

正常状态下,熔断器是关闭的一个状态,当出现调用失败、网络超时等就会处于打开的一种状态,当网络恢复之后就会处于半打开的一种状态。

  

  

circuitBreaker.enabled

熔断开启

circuitBreaker.requestVolumeThreshold

此属性设置时间窗口中请求断路的最小请求数。

例如,如果该值为20,那么如果在时间窗中仅接收19个请求(例如,10秒的时间窗),即使所有19个电路都失败,电路也不会跳闸。

circuitBreaker.sleepWindowInMilliseconds

熔断后的重试时间窗口,且在该时间窗口内只允许一次重试。即在熔断开关打开后,在该时间窗口允许有一次重试,如果重试成功,则将重置Health采样统计并闭合熔断开关实现快速恢复,否则熔断开关还是打开状态,执行快速失败。

circuitBreaker.errorThresholdPercentage

如果在一个采样时间窗口内,失败率超过该配置,则自动打开熔断开关实现降级处理,即快速失败。默认配置下采样周期为10s,失败率为50%。

在controller中访问方法是dept其中num的参数是2的就会在浏览器中提示服务器开小差的提示

    @Autowired
    private DeptService deptService;


    @HystrixCommand(fallbackMethod = "getfallback"
            ,commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60")
    })
    @RequestMapping(value = "/dept/get/{id}/{num}",method = RequestMethod.GET)
    public Dept dept (@PathVariable("id") Long id,@PathVariable("num") int num){
        if(num==2){
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return deptService.findById(id);
    }


    /**
     * 降级的服务的方法和返回值要和服务方法的方法一致
     * @param id
     * @return
     */
    public Dept HystrixProcess(@PathVariable("id") Long id,@PathVariable("num") int num){
        Dept dept=new Dept();
        dept.setDeptno(id);
        dept.setDname("服务开小差");
        dept.setDb_source("服务开小差");
        return dept;
    }

Feign中的Hystrix中的两种降级方式

第一种:

采用在接口调用服务的方式来做服务的熔断。

  • 在子类的工程中的公共模块中添加一个接口
     1 /**
     2  * DeptClientServiceFallbackFactory:实现该接口的类
     3  */
     4 @FeignClient(value = "zhservicecloud-dept",fallbackFactory = DeptClientServiceFallbackFactory.class)
     5 public interface DeptClientService {
     6 
     7 
     8     @RequestMapping(value = "/dept/add",method = RequestMethod.POST)
     9     public boolean add(@RequestBody Dept dept);
    10 
    11     @RequestMapping(value = "/dept/get/{id}",method = RequestMethod.GET)
    12     public Dept getdept (@PathVariable("id") Long id);
    13 
    14     @RequestMapping(value = "/dept/list",method = RequestMethod.GET)
    15     public List<Dept> findAlldept();
    16 
    17 }

    比如我是在对数据做的一系列操作模拟异常

  • 在子类的工程中的公共模块中添加的一个类
     1 /**
     2  * 实现接口:FallbackFactory
     3  *
     4  * DeptClientService接口
     5  */
     6 @Component
     7 public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService> {
     8     @Override
     9     public DeptClientService create(Throwable throwable) {
    10         return new DeptClientService() {
    11             @Override
    12             public boolean add(Dept dept) {
    13                 return false;
    14             }
    15 
    16             @Override
    17             public Dept getdept(Long id) {
    18                 return null;
    19             }
    20 
    21             @Override
    22             public List<Dept> findAlldept() {
    23                 System.out.println("Feign的第一种降级方式");
    24                 return null;
    25             }
    26         };
    27     }
    28 }
  • 在模块Feign的消费端的yml文件中追加配置
    1 feign:
    2   hystrix:
    3     enabled: true

    注意:这是在服务的消费端,如果想要设置熔断的其他都需要在服务的消费端设置

  • 在提供端的Controller中做测试
     1     @RequestMapping(value = "/dept/list",method = RequestMethod.GET)
     2     public List<Dept> dept()
     3     {
     4         try {
     5             Thread.sleep(2000);
     6         } catch (InterruptedException e) {
     7             e.printStackTrace();
     8         }
     9         return deptService.findAll();
    10     }

Feign的第二种降级方式

  • 同样是在子模块下的common模块下新建一个接口
     1 @FeignClient(value = "zhservicecloud-dept",fallbackFactory = DeptClientService1.DeptClientFallBack.class)
     2 public interface DeptClientService1 {
     3 
     4     @RequestMapping(value = "/dept/add",method = RequestMethod.POST)
     5     public boolean add(@RequestBody Dept dept);
     6 
     7     @RequestMapping(value = "/dept/get/{id}",method = RequestMethod.GET)
     8     public Dept getdept(@PathVariable("id") Long id);
     9 
    10     @RequestMapping(value = "/dept/list",method = RequestMethod.GET)
    11     public List<Dept> findAlldept();
    12 
    13 //    创建一个内部类
    14     @Component
    15     static class DeptClientFallBack implements DeptClientService1{
    16 
    17         @Override
    18         public boolean add(Dept dept) {
    19             return false;
    20         }
    21 
    22         @Override
    23         public Dept getdept(Long id) {
    24             return null;
    25         }
    26 
    27         @Override
    28         public List<Dept> findAlldept() {
    29             System.out.println("Feign第二种降级方式");
    30             return null;
    31         }
    32     }
    33 
    34 }
  • 在Feign的消费端中的Controller测试
     1 @RestController
     2 public class DeptController1 {
     3 
     4 
     5     @Autowired
     6     private DeptClientService1 deptClientService;
     7 
     8     @RequestMapping("/consumer1/dept/getdept/{id}")
     9     public Dept getDept(@PathVariable("id") Long id){
    10         return deptClientService.getdept(id);
    11     }
    12 
    13     @RequestMapping("/consumer1/dept/findall")
    14     public List<Dept> findAll(){
    15         return deptClientService.findAlldept();
    16     }
    17 }
原文地址:https://www.cnblogs.com/LBJLAKERS/p/12114227.html