你必须会的微服务之Hystrix熔断器

197 阅读8分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情

微服务已经成当前各大大厂追求的主流技术架构,学习微服务前景非常可观,而SpringCloud已成为主流微服务技术栈。本系列文章将以SpringCloud技术栈进行精讲,全方位剖析讲解SpringCloud技术栈在微服务场景下的实战应用,可以点赞关注,后续持续为大家更新。

Spring Cloud Hystrix

知识索引

  • 雪崩效应
  • Hystrix介绍
  • 案例演示
  • 全局fallback
  • Hystrix Dashboard监控平台

1 雪崩效应

分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务。如下图,对于同步调用,当库存服务不可用时,商品服务请求线程被阻塞,当有大批量请求调用库存服务时,最终可能导致整个商品服务资源耗尽,无法继续对外提供服务。并且这种不可用可能沿请求调用链向上传递,这种现象被称为雪崩效应。

170502_7fqS_2663573

所以,如果一个应用不能对来自依赖的故障进行隔离,那该应用本身就处在被拖垮的风险中。 因此,为了构建稳定、可靠的分布式系统,我们的服务应当具有自我保护能力,当依赖服务不可用时,当前服务启动自我保护功能,从而避免发生雪崩效应。

2 Hystrix介绍

Hystrix,英文意思是豪猪,全身是刺,因其背上长满棘刺,从而拥有了自我保护的能力。。

Hystrix Netflix 开源的一款容错系统,同样具有自我保护能力。

Hystrix用于隔离访问远程服务、第三方库、防止出现级联失败也就是雪崩效应

Hystrix具有以下特性:

请求熔断:类似于电路中的保险丝,当Hystrix Command请求后端服务失败数量超过一定比例(默认50%), 断路器会切换到开路状态(Open). 这时所有请求会直接失败而不会发送到后端服务. 断路器保持在开路状态一段时间后(默认5秒), 自动切换到半开路状态(HALF-OPEN).这时会判断下一次请求的返回情况, 如果请求成功, 断路器切回闭路状态(CLOSED), 否则重新切换到开路状态(OPEN). Hystrix的断路器就像我们家庭电路中的保险丝, 一旦后端服务不可用, 断路器会直接切断请求链, 避免发送大量无效请求影响系统吞吐量, 并且断路器有自我检测并恢复的能力。
服务降级:Fallback相当于是降级操作. 对于查询操作, 我们可以实现一个fallback方法, 当请求后端服务出现异常的时候, 可以使用fallback方法返回的值. fallback方法的返回值一般是设置的默认值或者来自缓存.告知后面的请求服务不可用了,不要再来了。
依赖隔离(采用舱壁模式,Docker就是舱壁模式的一种):在Hystrix中, 主要通过线程池来实现资源隔离. 通常在使用的时候我们会根据调用的远程服务划分出多个线程池.比如说,服务A的两个不同的接口分别调用了服务B和服务C,假设服务B出现了阻塞,同时服务B在服务A中对应的接口被频繁调用,由于服务B的阻塞导致了资源在调用B时被耗尽,此时其他请求服务A中服务C对应的接口时也会出现阻塞,为了避免这种情况Hystrix允许针对不同的服务调用配置不同的线程池,用以进行依赖隔离,如服务A中针对服务B和服务C的调用都配置了50个线程的线程池。此时如果在调用服务A时发生了阻塞,那么不会耗尽所有资源,此时服务A中的调用服务B的接口依然可以对外提供服务。
请求缓存:比如一个请求过来请求我userId=1的数据,你后面的请求也过来请求同样的数据,这时我不会继续走原来的那条请求链路了,而是把第一次请求缓存过了,把第一次的请求结果返回给后面的请求。
请求合并:利用一个合并处理器,将对同一个服务发起的连续请求合并成一个请求进行处理(这些连续请求的时间窗默认为10ms),在这个过程中涉及到的一个核心类就是HystrixCollapser。

Spring Cloud Hystrix是对Hystrix的封装,使得在Spring Cloud体系中使用Hystrix的特性变得十分容易

3 案例演示

接下来我们在service-consumer中演示Hystrix如何使用

3.1 引入依赖

service_consumerpom.xml中引入

<!--熔断Hystrix starter-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

3.2 开启熔断

通过@EnableCircuitBreaker注解开启熔断

/**
 * Copyright (c) 2022 itmentu.com, All rights reserved.
 *
 * @Author: yang
 */
@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
public class ServiceConsumerApplication {

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

    @Bean
    @LoadBalanced//开启负载均衡
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

3.3 开启服务降级

通过@HystrixCommand注解标记允许降级处理的接口及降级方法。

@GetMapping("/hello-loadbanlance")
@HystrixCommand(fallbackMethod ="fallBackMethod")
public String hello2(){
    // 1.通过注册中心的服务名构建url
    String url = "http://service-provider/hello";
    // 2.发送请求
    return restTemplate.getForObject(url,String.class);
}

@GetMapping("/hello-feign")
@HystrixCommand(fallbackMethod ="fallBackMethod")
public String hello3(){
    return helloFeign.hello();
}

// 熔断方法
public String fallBackMethod(){
    return "fail";
}

代码说明:

1:@HystrixCommand注解用来标记一个可熔断的接口方法
2:fallbackMethod=““表示触发熔断后的快速响应结果
3:需注意熔断方法的返回值必须和@HystrixCommand标记的接口返回值相同

3.4 配置熔断策略

# 配置熔断策略:
hystrix:
  command:
    default:
      circuitBreaker:
        forceOpen: false # 强制打开熔断器 默认false关闭的
        errorThresholdPercentage: 50 # 触发熔断错误比例阈值,默认值50%
        sleepWindowInMilliseconds: 5000  # 熔断后休眠时长,默认值5秒
        requestVolumeThreshold: 20  # 熔断触发最小请求次数,默认值是20
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 1000  # 熔断超时设置,默认为1秒

代码说明:

1:当Hystrix Command请求后端服务失败数量超过errorThresholdPercentage配置比例(默认50%),断路器会切换到开路状态(Open). 
2:这时所有请求会直接失败而不会发送到后端服务. 断路器保持在开路状态一段时间后(默认5秒), 自动切换到半开路状态(HALF-OPEN).
3:这时会判断下一次请求的返回情况, 如果请求成功, 断路器切回闭路状态(CLOSED), 否则重新切换到开路状态(OPEN). 
4:Hystrix的断路器就像我们家庭电路中的保险丝, 一旦后端服务不可用, 断路器会直接切断请求链, 避免发送大量无效请求影响系统吞吐量, 并且断路器有自我检测并恢复的能力。

3.5 测试

启动服务,调用

http://localhost:8002/consumer/hello-loadbanlance
http://localhost:8002/consumer/hello-feign

成功后,停止service-provider实例再次调用触发熔断

image-20220320170021670

image-20220320170043537

4 全局fallback

ConsumerController上添加@DefaultProperties注解,并通过defaultFallback配置默认fallback方法

@RestController
@RequestMapping("/consumer")
@DefaultProperties(defaultFallback="defaultFallBack")
public class ConsumerController {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private DiscoveryClient discoveryClient;
    @Autowired
    private HelloFeign helloFeign;

    @GetMapping("/hello")
    public String hello(){
        //1、获取Eureka中注册的provider-service实例列表
        List<ServiceInstance> serviceInstanceList = discoveryClient.getInstances("service-provider");
        //2、获取实例
        ServiceInstance serviceInstance = serviceInstanceList.get(0);
        //3、根据实例的信息拼接的请求地址
        String url = serviceInstance.getUri()+ "/hello";
        //4、发送请求
        return restTemplate.getForObject(url,String.class);
    }

    @GetMapping("/hello-loadbanlance")
    @HystrixCommand
    public String hello2(){
        // 1.通过注册中心的服务名构建url
        String url = "http://service-provider/hello";
        // 2.发送请求
        return restTemplate.getForObject(url,String.class);
    }

    @GetMapping("/hello-feign")
    @HystrixCommand
    public String hello3(){
        return helloFeign.hello();
    }

    // 全局熔断方法
    public String defaultFallBack(){
        return "fail";
    }
}

代码说明:

1:@DefaultProperties表示默认配置
2:该配置只会对和全局熔断方法返回值相同的接口方法生效
3:当配置了defaultFallback,@HystrixCommand中无需配置即可快速失败,当然也可以自行配置

5 Hystrix Dashboard监控平台

Hystrix官方提供了基于图形化的DashBoard(仪表板)监控平台。Hystrix仪表板可以显示每个断路器(被@HystrixCommand注解的方法)的状态。

5.1 pom依赖

<!--监控坐标-->
<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-dashboard</artifactId>
</dependency>

5.2 开启仪表板

/**
 * Copyright (c) 2022 itmentu.com, All rights reserved.
 *
 * @Author: yang
 */
@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
@EnableHystrixDashboard
public class ServiceConsumerApplication {

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

    @Bean
    @LoadBalanced//开启负载均衡
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

5.3 配置文件

#暴露全部监控信息,可以只填写hystrix.stream,也可以暴露全部 * ,注意在yml文件中特殊符号需要加引号
management:
  endpoints:
    web:
      exposure:
        include: '*'

5.4 控制台

访问http://localhost:8002/hystrix,添加需要监控的服务http://localhost:8002/turbine/turbine.stream

image-20220320173308448

image-20220320173503787