CircuitBreaker断路器

SpringCloud CircuitBreaker是一组用于微服务的断路器API,它底层支持Resilience4j、SpringRetry等多种实现,其中Resilience4j功能相对更为强大,因此实际开发中我们常使用它。

什么是断路器

首先我们了解一下什么是微服务架构中的断路器(Circuit Breaker)以及它能够解决的问题。在一个庞大的微服务系统中,假如某一个微服务出现故障,请求的数据迟迟不能返回,这可能造成其它依赖该功能的微服务出现阻塞,甚至耗尽服务器的线程资源,进而造成更大面积的问题。断路器就像保险丝,能够在服务出现问题时及时切断问题根源直接进行服务降级,而不是让其它服务苦苦等待,造成整个系统中的大面积故障。

总而言之,断路器主要能实现以下两个功能:

  1. 提供熔断机制,避免单个微服务故障引起大面积故障
  2. 提供回退方案,在请求失败时执行回退逻辑

断路器的工作机制:断路器有3种工作状态,关闭、打开和半打开。一段时间内,某个微服务请求失败次数在一定阈值内,熔断器关闭;超过一定阈值后,说明服务存在故障,熔断器打开,请求该服务将立即失败;处于打开状态的熔断器一段时间后将处于半打开状态,并执行一定量的请求,如果请求成功了,熔断器会再次切换为关闭状态。

SpringCloud CircuitBreaker和Resilience4j的关系

这里不得不再补充一些历史。在SpringCloud早期,断路器的实现是Netflix开源的Hystrix,但由于Netflix公司弃坑了该项目,SpringCloud转而选择集成其它实现,而且这里Spring选择了一种更通用的方式,Spring官方定义了一组抽象API即SpringCloud CircuitBreaker,其它库需要实现该API来作为断路器集成到SpringCloud,而Resilience4j就是这样的一种实现。

SpringCloud CircuitBreaker集成Resilience4j的起步依赖库是spring-cloud-starter-circuitbreaker-resilience4j,不过Resilience4j还有很多额外的功能,因此Resilience4j官方提供了spring-cloud-starter-resilience4j起步依赖库,如果我们只是用SpringCloud CircuitBreaker API,那么我们引入前者就行了,如果我们需要用到Resilience4j中相比SpringCloud CircuitBreaker多出来的那部分功能,就需要使用后者。

引入Maven依赖

要使用SpringCloud CircuitBreaker和Resilience4j,我们需要引入以下依赖。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>

CircuitBreaker相关配置

SpringCloud CircuitBreaker能够和SpringCloud OpenFeign集成在一起使用,我们可以在application.properties中进行配置,下面例子包含一些常用配置。

# 在OpenFeign中启用CircuitBreaker
feign.circuitbreaker.enabled=true
feign.circuitbreaker.alphanumeric-ids.enabled=true

# CircuitBreaker的超时时间
resilience4j.timelimiter.configs.default.timeout-duration=3s

# 断路器打开的失败阈值
resilience4j.circuitbreaker.configs.default.failure-rate-threshold=50
# 断路器打开的最小请求数
resilience4j.circuitbreaker.configs.default.minimum-number-of-calls=10
# 触发熔断后等待多久开始尝试恢复
resilience4j.circuitbreaker.configs.default.wait-duration-in-open-state=5000ms

其中我们用到了很多default配置,它指定了所有的断路器实例的配置,我们也可以专门配置一个断路器名,例如resilience4j.timelimiter.instances.ProductClient.timeout-duration=1s,该配置就单独为ProductClient这个名字对应的断路器进行配置,且具有更高的优先级。

使用断路器实现服务降级

下面例子中,我们使用SpringCloud CircuitBreaker实现了快速失败功能,当order服务调用productClient.findProductById()接口触发熔断时,在指定时间内该服务对此接口的调用会直接返回null

package com.gacfox.demo.order.controller;

import com.gacfox.demo.product.api.ProductClient;
import com.gacfox.demo.product.model.Product;
import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreakerFactory;
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.function.Function;
import java.util.function.Supplier;

@RestController
@RequestMapping("/api/v1/order")
public class OrderController {
    @Resource
    private Resilience4JCircuitBreakerFactory circuitBreakerFactory;
    @Resource
    private ProductClient productClient;

    @GetMapping("/callProductService")
    public Product callProductService() {
        CircuitBreaker circuitBreaker = circuitBreakerFactory.create("ProductClient");
        Supplier<Product> productSupplier = () -> productClient.findProductById(1L);
        Function<Throwable, Product> fallbackFunc = throwable -> null;
        return circuitBreaker.run(productSupplier, fallbackFunc);
    }
}

SpringCloud CircuitBreaker的API设计吸收了很多Java8函数式编程的风格。代码中,我们首先使用Resilience4JCircuitBreakerFactory工厂类创建了CircuitBreaker对象,它需要指定一个名字以便与前面application.properties中的配置关联;之后我们提供了一个Supplier对象,其中的代码就是用OpenFeign请求微服务接口;我们还创建了一个Function对象,其中包含的是失败的回退逻辑,这里我们只是简单的直接返回null,实际开发中可能采用一些其它降级方式,比如返回一个通用的错误对象,或是一个老的缓存等;最后我们调用circuitBreaker.run()方法,传入Supplier和回退Function

此时SpringCloud CircuitBreaker就生效了,我们可以在ProductClient对应的微服务中尝试插入一些Thread.sleep()来模拟接口迟迟不能返回的状况,并不断访问/callProductService,查看断路器熔断效果。

查看断路器状态

Resilience4J没有直接提供类似Hystrix的监控图形界面来观察相关的状态信息,但Resilience4J能够集成到Actuator中,我们可以通过监控端点来实时查看Resilience4J的状态,注意这需要引入Actuator的依赖。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

application.properties进行如下配置后,我们就可以在/actuator/health中通过Health端点查看断路器的状态。

management.endpoint.health.show-details=always
management.health.circuitbreakers.enabled=true
resilience4j.circuitbreaker.configs.default.register-health-indicator=true

此外,我们还可以通过访问/actuator/metrics查看到Resilience4J相关的Metrics监控端点名,我们可以访问这些具体的监控端点,来查看Resilience4J的其它状态信息。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap