回顾之前文章:微服务熔断处理之断路器Resilience4j(一)中介绍了 Resilience4j 的一些基本功能,这些基本功能涵盖了请求熔断、限流、以及重试等功能,以及Resilience4j 的一些基本用法。本文将详解Resilience4j-circuitbreaker组件;
1、CiruitBreaker(熔断器)模块概述
Resilience4j的CircuitBreaker主要由6个部分组成:管理熔断器实例的注册容器、熔断器的相关配置、熔断器的各种状态、触发熔断器状态变化的指标、熔断器行为变化产生的事件以及熔断器本身。
它们之间的基本调用关系如下图:
2、CircuitBreaker模块详解
2.1 CircuitBreakerRegistry(熔断器容器)
CircuitBreakerRegistry接口的实现类InMemoryCircuitBreakerRegistry在内部使用ConcurrentHashMap容器来存储CircuitBreaker实例,保证了并发安全及原子性。通过CircuitBreakerRegistry可以创建新的CircuitBreaker实例及检索创建的CircuitBreaker实例。
主要关注的源码如下:
(在CircuitBreakerRegistry接口中使用static方法实现了线程安全的单例模式)
public interface CircuitBreakerRegistry {
// 返回所有的CircuitBreaker实例
Seq<CircuitBreaker> getAllCircuitBreakers();
// 根据名称返回CircuitBreaker实例,
// 如果不存在则根据默认配置,创建CircuitBreaker实例并返回
CircuitBreaker circuitBreaker(String name);
// 根据名称返回CircuitBreaker实例,
// 如果不存在则 根据传入的配置实例,创建CircuitBreaker实例并返回
CircuitBreaker circuitBreaker(String name, CircuitBreakerConfig circuitBreakerConfig);
// 同上
CircuitBreaker circuitBreaker(String name, Supplier<CircuitBreakerConfig> circuitBreakerConfigSupplier);
// 根据自定义的配置,创建CircuitBreakerRegistry实例
// 线程安全的单例
static CircuitBreakerRegistry of(CircuitBreakerConfig circuitBreakerConfig){
return new InMemoryCircuitBreakerRegistry(circuitBreakerConfig);
}
// 使用默认配置,创建CircuitBreakerRegistry实例
// 线程安全的单例
static CircuitBreakerRegistry ofDefaults(){
return new InMemoryCircuitBreakerRegistry();
}
}
在InMemoryCircuitBreakerRegistry实现类中,主要做了2件事:创建了ConcurrentHashMap实例及调用CricuitBreaker.of(…)方法创建CircuitBreaker实例。
final class InMemoryCircuitBreakerRegistry implements CircuitBreakerRegistry {
private final CircuitBreakerConfig defaultCircuitBreakerConfig;
private final ConcurrentMap<String, CircuitBreaker> circuitBreakers;
public InMemoryCircuitBreakerRegistry() {
// 创建默认配置实例
this.defaultCircuitBreakerConfig = CircuitBreakerConfig.ofDefaults();
// 创建并发安全的容器放置CircuitBreaker实例
this.circuitBreakers = new ConcurrentHashMap<>();
}
......
// 调用CircuitBreaker.of(...)方法创建CircuitBreaker实例
@Override
public CircuitBreaker circuitBreaker(String name) {
return circuitBreakers.computeIfAbsent(Objects.requireNonNull(name, "Name must not be null"), (k) -> CircuitBreaker.of(name, defaultCircuitBreakerConfig));
}
}
2.2 CircuitBreakerConfig(熔断器配置)
CircuitBreakerConfig类中封装了与熔断器相关的配置属性,属性包括:请求调用失败的阈值、熔断器在打开状态时的持续时间、熔断器在半开状态下的Ring Buffer大小、熔断器在关闭状态下的Ring Buffer大小、是否记录请求调用失败的断言等。 Ring Buffer的原理在后面研究CircuitBreakerMetrics部分时再详细讲解,现在只需要了解,它是一个存储每次请求调用成功与否的环形缓存区。
滑动窗口的类型:
- 基于计数的滑动窗口(默认,CircuitBreakerConfig可看出)
- 基于时间的滑动窗口
public enum SlidingWindowType {
TIME_BASED, COUNT_BASED
}
CircuitBreakerConfig 类定义了相关配置与属性,主要有如下:
//请求调用失败的阈值,百分比。默认是50%,即服务A调用服务B,此时B调用失败即算作一个失败调用
public static final int DEFAULT_FAILURE_RATE_THRESHOLD = 50; // Percentage
//慢调用的阈值,百分比
public static final int DEFAULT_SLOW_CALL_RATE_THRESHOLD = 100; // Percentage
// 熔断器在打开状态时的持续时间。默认是60秒
public static final int DEFAULT_WAIT_DURATION_IN_OPEN_STATE = 60; // Seconds
// 熔断器在半开状态下的ring buffer大小。默认10,不超过此值就可以通过请求
public static final int DEFAULT_PERMITTED_CALLS_IN_HALF_OPEN_STATE = 10;
// 熔断器在关闭状态下的可以计算失败率的最小值,默认100
public static final int DEFAULT_MINIMUM_NUMBER_OF_CALLS = 100;
//滑动窗口大小,熔断器在关闭状态下的ring buffer大小
public static final int DEFAULT_SLIDING_WINDOW_SIZE = 100;
//慢调用的时间,即当服务A调用服务B时,B的执行时间超过了60秒就算作是慢调用
public static final int DEFAULT_SLOW_CALL_DURATION_THRESHOLD = 60; // Seconds
//滑动窗口类型,默认为基于计数的 COUNT_BASED
public static final SlidingWindowType DEFAULT_SLIDING_WINDOW_TYPE = SlidingWindowType.COUNT_BASED;
public static final boolean DEFAULT_WRITABLE_STACK_TRACE_ENABLED = true;
// 是否记录请求调用失败的断言,默认所有异常都记录
private static final Predicate<Throwable> DEFAULT_RECORD_EXCEPTION_PREDICATE = throwable -> true;
//忽略异常
private static final Predicate<Throwable> DEFAULT_IGNORE_EXCEPTION_PREDICATE = throwable -> false;
// The default exception predicate counts all exceptions as failures.
private Predicate<Throwable> recordExceptionPredicate = DEFAULT_RECORD_EXCEPTION_PREDICATE;
// The default exception predicate ignores no exceptions.
private Predicate<Throwable> ignoreExceptionPredicate = DEFAULT_IGNORE_EXCEPTION_PREDICATE;
// 默认为false,是否自动从打开到半开,当waitDurationInOpenState时间一过,是否自动从OPEN切换到HALF_OPEN
// true:waitDurationInOpenState到期后open自动变为half_open
//false,得等到再有请求后状态才会变为half_open,否则即使waitDurationInOpenState到期状态依然是open
private boolean automaticTransitionFromOpenToHalfOpenEnabled = false;
CircuitBreakerConfig类通过Builder模式构造CircuitBreakerConfig实例及流式的设置配置属性值:
/**
* 构造者模式
*/
public static class Builder {
// 请求调用失败,存储异常记录的集合
private Class<? extends Throwable>[] recordExceptions = new Class[0];
// 请求调用失败,忽略异常记录的集合
private Class<? extends Throwable>[] ignoreExceptions = new Class[0];
/**
* 异常记录集合与异常忽略集合取交集,如果有值则为false,否则为true。
*/
private void buildErrorRecordingPredicate() {
this.errorRecordingPredicate =
getRecordingPredicate()
.and(buildIgnoreExceptionsPredicate()
.orElse(DEFAULT_RECORD_FAILURE_PREDICATE));
}
}
CircuitBreakerConfig提供了两种获取Builder对象的方法:使用默认配置和自定义配置:
/**
* Returns a builder to create a custom CircuitBreakerConfig.
* 1.使用默认配置创建Builder对象,得到builder对象就可以根据builder提供的方法改变配置
* @return a {@link Builder}
*/
public static Builder custom() {
return new Builder();
}
/**
* Returns a builder to create a custom CircuitBreakerConfig based on another
* CircuitBreakerConfig.
* 2.使用传入的自定义的配置baseConfig的builder对象,得到builder对象就可以根据builder提供的方法改变配置
* @return a {@link Builder}
*/
public static Builder from(CircuitBreakerConfig baseConfig) {
return new Builder(baseConfig);
}
常用yml文件配置参考:
resilience4j.circuitbreaker:
configs:
default: # @CircuitBreaker的name
registerHealthIndicator: true #健康监测
ringBufferSizeInClosedState: 2 # 熔断器关闭时的缓冲区大小,不会限制线程的并发量,在熔断器发生状态转换前所有请求都会调用后端服务(缓冲区满时才会计算失败率)
ringBufferSizeInHalfOpenState: 1 # 熔断器半开时的缓冲区大小,会限制线程的并发量(只允许ringBufferSizeInHalfOpenState个并发),
# 例如缓冲区为10则每次只会允许10个请求调用后端服务
# 之所以能限制并发,CircuitBreakerStateMachine使用了AtomicInteger:this.permittedNumberOfCalls = new AtomicInteger(permittedNumberOfCallsInHalfOpenState);
waitDurationInOpenState: 10s # 熔断器从打开到半开需要的时间
failureRateThreshold: 50 # 熔断器打开的失败阈值或半开状态使用的同一个失败率阈值
slowCallDurationThreshold: 600s # 慢调用的时间,单位s
slowCallRateThreshold: 100 # 慢调用的比例阈值
eventConsumerBufferSize: 7 # 事件缓冲区大小
minimumNumberOfCalls: 4 #默认100
# slideWindowType: COUNT_BASED # 配置滑动窗口的类型,默认为count_based
# automaticTransitionFromOpenToHalfOpenEnabled: false # 默认为false,是否自动从打开到半开,当waitDurationInOpenState时间一过,是否自动从OPEN切换到HALF_OPEN
# # true:waitDurationInOpenState到期后open自动变为half_open,
# #如果为false,得等到再有请求后状态才会变为half_open,否则即使waitDurationInOpenState到期状态依然是open
recordExceptions: # 记录的异常
- org.springframework.web.client.HttpServerErrorException
- java.io.IOException
- java.util.concurrent.TimeoutException
- org.springframework.web.client.ResourceAccessException
- org.springframework.web.client.HttpClientErrorException
ignoreExceptions: # 忽略的异常
recordFailurePredicate: #用于判断哪些异常应该算作失败纳入断路器统计,默认是Throwable类型
2.3 CircuitBreakerState(熔断器状态)
熔断器的有限状态机
CircuitBreaker的状态转换通过一个有限状态机来实现的,有3种常用状态: 关闭(CLOSED)、打开(OPEN)、半开(HALF_OPEN)和2种特定状态:不可用(DISABLED)、强制打开(FORCE_OPEN)。
状态转换关系如图:
-
CLOSED ==> OPEN:单向转换。当请求失败率超过阈值时,熔断器的状态由关闭状态转换到打开状态。失败率的阈值默认50%,可以通过设置CircuitBreakerConfig实例的failureRateThreshold属性值进行改变。
-
OPEN <==> HALF_OPEN:双向转换。打开状态的持续时间结束,熔断器的状态由打开状态转换到半开状态。这时允许一定数量的请求通过,当这些请求的失败率超过阈值,熔断器的状态由半开状态转换回打开状态。半开时请求的数量是由CircuitBreakerConfig实例的ringBufferSizeInHalfOpenState属性值设置的。
-
HALF_OPEN ==> CLOSED:如果请求失败率小于或等于阈值,则熔断器的状态由半开状态转换到关闭状态。
-
DISABLED和FORCE_OPEN这2种状态仅仅是表示退出上面3种状态时的临界状态标识,这2种状态不会被记录到统计指标中,也不会发送状态转换事件。
状态转换接口源码:
//熔断器切换到不可用状态
public void transitionToDisabledState() {
stateTransition(DISABLED, currentState -> new DisabledState(this));
}
//熔断器切换到强制开启状态
public void transitionToForcedOpenState() {
stateTransition(FORCED_OPEN, currentState -> new ForcedOpenState(this));
}
//熔断器切换到关闭状态
public void transitionToClosedState() {
stateTransition(CLOSED, currentState -> new ClosedState(this, currentState.getMetrics()));
}
//熔断器切换到开启状态
public void transitionToOpenState() {
stateTransition(OPEN, currentState -> new OpenState(this, currentState.getMetrics()));
}
//熔断器切换到半开状态
public void transitionToHalfOpenState() {
stateTransition(HALF_OPEN, currentState -> new HalfOpenState(this));
}
//熔断器熔断状态转换
private void stateTransition(State newState, Function<CircuitBreakerState, CircuitBreakerState> newStateGenerator) {
CircuitBreakerState previousState = stateReference.getAndUpdate(currentState -> {
//若当前状态与更新状态一样,则返回
if (currentState.getState() == newState) {
return currentState;
}
//若当前状态与更新状态不一样,切换到新状态
return newStateGenerator.apply(currentState);
});
//状态发生了变化,则发布状态转换事件。evenType为:Type.STATE_TRANSITION
if (previousState.getState() != newState) {
publishStateTransitionEvent(StateTransition.transitionBetween(previousState.getState(), newState));
}
}
从源码可以看出状态转换通过AtomicReference来保证原子操作,从而实现thread-safe。
状态的实现
下面我们看看Resilience4j是如何实现有限状态机的。将状态机的5种状态封装成5个对应的类,把这些状态的公共属性及公共行为抽象出来封装成抽象类CircuitBreakerState。如图:
这些状态类都需要一个状态机属性CircuitBreakerStateMachine,用来驱动状态之间的转换。
// 有限状态机实例,内部实现了状态转换机制
CircuitBreakerStateMachine stateMachine;
- CircuitBreakerStateMachine实现了CircuitBreakerStateMachine接口
- AtomicReference用来记录当前断路器的状态
- 状态转换接口内部都调用了stateTransition方法,里头主要是更新AtomicReference以及发布事件
- stateTransition以及reset方法里头都调用了StateTransition.transitionBetween来发布事件
- CircuitBreakerEventProcessor用来处理事件
CircuitBreakerState的公共属性:
/**
* Abstract state of the CircuitBreaker state machine.
*/
abstract class CircuitBreakerState{
CircuitBreakerStateMachine stateMachine;
CircuitBreakerState(CircuitBreakerStateMachine stateMachine) {
this.stateMachine = stateMachine;
}
abstract boolean isCallPermitted();
abstract void onError(Throwable throwable);
abstract void onSuccess();
abstract CircuitBreaker.State getState();
abstract CircuitBreakerMetrics getMetrics();
/**
* Should the CircuitBreaker in this state publish events
* @return a boolean signaling if the events should be published
*/
boolean shouldPublishEvents(CircuitBreakerEvent event){
return event.getEventType().forcePublish || getState().allowPublish;
}
}
- CircuitBreakerState与CircuitBreakerStateMachine二者相互保存各自的引用
- CircuitBreakerState的子类有OpenState、HalfOpenState、ForcedOpenState、ClosedState、DisabledState
- 每个子类的onError、onSuccess方法自己判断是否进行状态转移,如果要转移会调用CircuitBreakerStateMachine的transitionTo开头的方法
CircuitBreakerEventProcessor:
/**
* CircuitBreakerEventProcessor继承了EventProcessor,处理CircuitBreakerEvent事件
* CircuitBreakerEventProcessor也实现了EventConsumer以及EventPublisher接口
*/
private class CircuitBreakerEventProcessor extends
EventProcessor<CircuitBreakerEvent> implements
EventConsumer<CircuitBreakerEvent>, EventPublisher {
/**
* onSuccess、onError、onStateTransition、onReset、
* onIgnoredError、onCallNotPermitted里头调用了registerConsumer方法
*/
@Override
public EventPublisher onSuccess(EventConsumer<CircuitBreakerOnSuccessEvent> onSuccessEventConsumer) {
registerConsumer(CircuitBreakerOnSuccessEvent.class, onSuccessEventConsumer);
return this;
}
@Override
public EventPublisher onError(EventConsumer<CircuitBreakerOnErrorEvent> onErrorEventConsumer) {
registerConsumer(CircuitBreakerOnErrorEvent.class, onErrorEventConsumer);
return this;
}
@Override
public EventPublisher onStateTransition(EventConsumer<CircuitBreakerOnStateTransitionEvent> onStateTransitionEventConsumer) {
registerConsumer(CircuitBreakerOnStateTransitionEvent.class, onStateTransitionEventConsumer);
return this;
}
@Override
public EventPublisher onReset(EventConsumer<CircuitBreakerOnResetEvent> onResetEventConsumer) {
registerConsumer(CircuitBreakerOnResetEvent.class, onResetEventConsumer);
return this;
}
@Override
public EventPublisher onIgnoredError(EventConsumer<CircuitBreakerOnIgnoredErrorEvent> onIgnoredErrorEventConsumer) {
registerConsumer(CircuitBreakerOnIgnoredErrorEvent.class, onIgnoredErrorEventConsumer);
return this;
}
@Override
public EventPublisher onCallNotPermitted(EventConsumer<CircuitBreakerOnCallNotPermittedEvent> onCallNotPermittedEventConsumer) {
registerConsumer(CircuitBreakerOnCallNotPermittedEvent.class, onCallNotPermittedEventConsumer);
return this;
}
/**
* consumeEvent里头则是调用了processEvent方法
*/
@Override
public void consumeEvent(CircuitBreakerEvent event) {
super.processEvent(event);
}
}
- CircuitBreakerEventProcessor继承了EventProcessor,处理CircuitBreakerEvent事件
- CircuitBreakerEventProcessor也实现了EventConsumer以及EventPublisher接口
- onSuccess、onError、onStateTransition、onReset、onIgnoredError、onCallNotPermitted里头调用了registerConsumer方法
- consumeEvent里头则是调用了processEvent方法
EventProcessor:
public class EventProcessor<T> implements EventPublisher<T> {
protected volatile boolean consumerRegistered;
private volatile EventConsumer<T> onEventConsumer;
private ConcurrentMap<Class<? extends T>, EventConsumer<Object>> eventConsumers = new ConcurrentHashMap<>();
public boolean hasConsumers(){
return consumerRegistered;
}
/**
* registerConsumer方法主要是往eventConsumers设置事件类型的消费者
*/
@SuppressWarnings("unchecked")
public <E extends T> void registerConsumer(Class<? extends E> eventType, EventConsumer<E> eventConsumer){
consumerRegistered = true;
eventConsumers.put(eventType, (EventConsumer<Object>) eventConsumer);
}
/**
* processEvent方法主要是查找相应的事件消费者去处理事件
*/
@SuppressWarnings("unchecked")
public <E extends T> boolean processEvent(E event) {
boolean consumed = false;
if(onEventConsumer != null){
onEventConsumer.consumeEvent(event);
consumed = true;
}
if(!eventConsumers.isEmpty()){
EventConsumer<T> eventConsumer = (EventConsumer<T>) eventConsumers.get(event.getClass());
if(eventConsumer != null){
eventConsumer.consumeEvent(event);
consumed = true;
}
}
return consumed;
}
@Override
public void onEvent(EventConsumer<T> onEventConsumer) {
consumerRegistered = true;
this.onEventConsumer = onEventConsumer;
}
}
- registerConsumer方法主要是往eventConsumers设置事件类型的消费者
- processEvent方法主要是查找相应的事件消费者去处理事件
EventPublisher:
/**
* 这个EventPublisher接口继承了io.github.resilience4j.core.EventPublisher
*
* 这些on方法分别处理了CircuitBreakerOnSuccessEvent、CircuitBreakerOnErrorEvent、
* CircuitBreakerOnStateTransitionEvent、CircuitBreakerOnResetEvent、
* CircuitBreakerOnIgnoredErrorEvent、CircuitBreakerOnCallNotPermittedEvent事件
*
* CircuitBreakerEvent接口定义了事件的Type枚举
* 规范了getCircuitBreakerName、getEventType、getCreationTime方法
*/
interface EventPublisher extends io.github.resilience4j.core.EventPublisher<CircuitBreakerEvent> {
EventPublisher onSuccess(EventConsumer<CircuitBreakerOnSuccessEvent> eventConsumer);
EventPublisher onError(EventConsumer<CircuitBreakerOnErrorEvent> eventConsumer);
EventPublisher onStateTransition(EventConsumer<CircuitBreakerOnStateTransitionEvent> eventConsumer);
EventPublisher onReset(EventConsumer<CircuitBreakerOnResetEvent> eventConsumer);
EventPublisher onIgnoredError(EventConsumer<CircuitBreakerOnIgnoredErrorEvent> eventConsumer);
EventPublisher onCallNotPermitted(EventConsumer<CircuitBreakerOnCallNotPermittedEvent> eventConsumer);
}
AbstractCircuitBreakerEvent:
/**
* 定义了circuitBreakerName、creationTime属性
* 重写了getCircuitBreakerName、getCreationTime方法
* CircuitBreakerOnSuccessEvent、CircuitBreakerOnErrorEvent、
* CircuitBreakerOnStateTransitionEvent、CircuitBreakerOnResetEvent、
* CircuitBreakerOnIgnoredErrorEvent、CircuitBreakerOnCallNotPermittedEvent都是从
* AbstractCircuitBreakerEvent继承而来,个别的自定义了自己的属性,主要是重写getEventType以及toString方法
*/
abstract class AbstractCircuitBreakerEvent implements CircuitBreakerEvent {
private final String circuitBreakerName;
private final ZonedDateTime creationTime;
AbstractCircuitBreakerEvent(String circuitBreakerName) {
this.circuitBreakerName = circuitBreakerName;
this.creationTime = ZonedDateTime.now();
}
@Override
public String getCircuitBreakerName() {
return circuitBreakerName;
}
@Override
public ZonedDateTime getCreationTime() {
return creationTime;
}
}
- 定义了circuitBreakerName、creationTime属性
- 重写了getCircuitBreakerName、getCreationTime方法
- CircuitBreakerOnSuccessEvent、CircuitBreakerOnErrorEvent、CircuitBreakerOnStateTransitionEvent、CircuitBreakerOnResetEvent、CircuitBreakerOnIgnoredErrorEvent、CircuitBreakerOnCallNotPermittedEvent都是从AbstractCircuitBreakerEvent继承而来,个别的自定义了自己的属性,主要是重写getEventType以及toString方法
总结:
CircuitBreakerStateMachine里头维护了一个AtomicReference引用,对应的onError及onSuccess方法都委托给改引用对应的状态的onError以及onSuccess方法
子类的onError以及onSuccess方法方法则自行判断是否需要进行状态切换以及切换到什么状态,自己调用CircuitBreakerStateMachine的transitionTo开头的方法,来改变AtomicReference的值(借助子类的各自实现来化解状态转换的复杂逻辑),同时发布一些事件。