![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/dd563e51299776e6517cc65cdb7be16d.jpeg#pic_center)
一:CircuitBreakerState状态的实现
CircuitBreaker有5种状态,把这5种状态的公共属性和行为抽象到CircuitBreakerState,然后5种状态ClosedState、OpenState、DisabledState、ForcedOpenState、HalfOpenState分别去实现各自的行为
其中公共行为有:
//把5种状态的公共属性及公共行为抽象出来封装成抽象类CircuitBreakerState
private interface CircuitBreakerState {
//是否可以尝试获取信号量,其实就是一个AtomicBoolean变量
boolean tryAcquirePermission();
//获取信号量,根据是否获取信号量来作为是否允许请求调用后端接口的判断
//close没有实现
//open,halfOpen,ForcedOpen:如果仍是open状态并请求,直接报错
void acquirePermission();
// 释放信号量
//close,open ,ForcedOpen没有实现
//HalfOpen,将permittedNumberOfCalls+1 ???
void releasePermission();
//请求调用失败,记录指标,当达到设定的度量指标后,调用状态机实例触发状态转换
//1.先记录请求,即把对应的总请求次数,错误请求次数等+1,再计算错误率/慢调用率等是否达到阈值 (记录请求是AbstractAggregation实现,计算错误率等是CircuitBreakerMetrics计算的,后面讲到)
//2. 根据result是否达到阈值结果,若是,则调用stateTransition更改状态
void onError(long duration, TimeUnit durationUnit, Throwable throwable);
//请求调用成功,记录指标,当达到设定的度量指标后,调用状态机实例触发状态转换
void onSuccess(long duration, TimeUnit durationUnit);
int attempts();
//返回当前circuitBreaker的状态
CircuitBreaker.State getState();
//返回当前状态的封装了度量指标的类实例
CircuitBreakerMetrics getMetrics();
/**
* Should the CircuitBreaker in this state publish events
* 是否要发布事件(先看是否设置了强制发布事件或允许发布)
* @return a boolean signaling if the events should be published
*/
default boolean shouldPublishEvents(CircuitBreakerEvent event) {
return event.getEventType().forcePublish || getState().allowPublish;
}
}
- 通过各自的实现可以发现,当是DisabledState 和 ForcedOpenState状态时,他们的行为不会被记录,更不会发布状态转换事件,即onError() 和 onSusses()都没有实现;
- 只有当tryAcquirePermission()为判断是否可以将该请求通过,如果某状态可能返回false时,acquirePermission()会再次调用tryAcquirePermission()检查是否可以通过,如果false,就抛CallNotPermittedException异常,其中因为CloseStat状态永远返回true,所以acquirePermission()不再校验
- onError()和onSuccess()作用为:记录请求,计算错误率,慢调用率等,如果达到阈值,则更改状态,具体如何实现是由CircuitBreakerMetrics和AbstractAggregation实现
- 其中OpenState创建特别之处是,如果设置了自动 从开开到半开
automaticTransitionFromOpenToHalfOpenEnabled: true
,则需要
OpenState(final int attempts, CircuitBreakerMetrics circuitBreakerMetrics) {
this.attempts = attempts;
final long waitDurationInMillis = circuitBreakerConfig
.getWaitIntervalFunctionInOpenState().apply(attempts);
this.retryAfterWaitDuration = clock.instant().plus(waitDurationInMillis, MILLIS);
this.circuitBreakerMetrics = circuitBreakerMetrics;
if (circuitBreakerConfig.isAutomaticTransitionFromOpenToHalfOpenEnabled()) {
//如果设置了自动 从开开到半开 ,则需要设置一个 waitDurationInOpenState秒之后的守候线程去将状态从打开改为半开
ScheduledExecutorService scheduledExecutorService = schedulerFactory.getScheduler();
//调用 OpenStat的toHalfOpenState()更改状态为半开
scheduledExecutorService
.schedule(this::toHalfOpenState, waitDurationInMillis, TimeUnit.MILLISECONDS);
}
isOpen = new AtomicBoolean(true);
}
二:CircuitBreaker 熔断器
- CircuitBreaker接口定义了5种状态的的枚举值enum State,其中包括状态是否允许发布事件,还定义了所有可能发生的两只之间的状态转换 enum
/**
* 状态的枚举类型
* 为了方便进行判等操作,同时也设置了每种状态是否允许发布事件
* States of the CircuitBreaker state machine.
*/
enum State {
//是否允许发布事件
public final boolean allowPublish;
private final int order;
。。。。
State(int order, boolean allowPublish) {
this.order = order;
this.allowPublish = allowPublish;
}
}
/**
* State transitions of the CircuitBreaker state machine.
* 有限状态机所有可能发生的状态转换,主要用于在状态转换事件中表示哪两种状态发生了转换
*/
enum StateTransition {
。。。
// 提供方法根据两个状态返回状态转换的枚举
public static StateTransition transitionBetween(String name, State fromState,
State toState) {
final StateTransition stateTransition = STATE_TRANSITION_MAP
.get(Tuple.of(fromState, toState));
if (stateTransition == null) {
throw new IllegalStateTransitionException(name, fromState, toState);
}
return stateTransition;
}
- 声明了Metrics度量接口,由CircuitBreakerMetrics实现,在后面文章会讲到
- 声明了EventPublisher 事件处理器接口,继承core.EventPublisher,由CircuitBreakerStateMachine.CircuitBreakerEventProcessor实现,用于向EventProcessor中注册处理六种事件的EventConsumer,也用于处理事件,在后面文章会讲到
- 提供了2类静态生成CircuitBreakerStateMachine实例的方法,使用默认配置,自定义配置间接调用CircuitBreakerStateMachine构造函数创建实例
//可以利用此方法,不经过注册中心,直接创建名为name,配置为默认配置的熔断器
static CircuitBreaker ofDefaults(String name) {
return new CircuitBreakerStateMachine(name);
}
// 直接创建名为name,指定配置的熔断器
static CircuitBreaker of(String name, CircuitBreakerConfig circuitBreakerConfig) {
return new CircuitBreakerStateMachine(name, circuitBreakerConfig);
}
static CircuitBreaker of(String name, CircuitBreakerConfig circuitBreakerConfig,
io.vavr.collection.Map<String, String> tags) {
return new CircuitBreakerStateMachine(name, circuitBreakerConfig, tags);
}
//直接创建名为name,指定配置的熔断器,使用java的supplier
static CircuitBreaker of(String name,
Supplier<CircuitBreakerConfig> circuitBreakerConfigSupplier) {
return new CircuitBreakerStateMachine(name, circuitBreakerConfigSupplier);
}
static CircuitBreaker of(String name,
Supplier<CircuitBreakerConfig> circuitBreakerConfigSupplier,
io.vavr.collection.Map<String, String> tags) {
return new CircuitBreakerStateMachine(name, circuitBreakerConfigSupplier, tags);
}
- 19个default方法,这些default方法调用static方法,采用装饰器模式,可以使用
CircuitBreaker.decorateCheckedSupplier() / CircuitBreaker.decorateCheckedRunnable() / CircuitBreaker.decorateCheckedFunction()
装饰 Supplier / Runnable / Function / CheckedRunnable / CheckedFunction,然后使用Vavr的Try.of(…) / Try.run(…) 调用被装饰的函数,我们项目就利用了此功能,也可以使用map / flatMap / filter / recover / andThen链接更多的函数。函数链只有在熔断器处于关闭或半开状态时才可以被调用介绍其一decorateSupplier()方法:
static <T> Supplier<T> decorateSupplier(CircuitBreaker circuitBreaker, Supplier<T> supplier) {
return () -> {
//获取信号量,调用顺序 CircuitBreakerStateMachine.acquirePermission ->CircuitBreakerState.acquirePermission
circuitBreaker.acquirePermission();
long start = System.nanoTime();
try {
//执行被装饰的方法
T returnValue = supplier.get();
long durationInNanos = System.nanoTime() - start;
//调用成功:记录请求,发布事件
//调用顺序 CircuitBreakerStateMachine.onSuccess ->CircuitBreakerState.onSuccess
circuitBreaker.onSuccess(durationInNanos, TimeUnit.NANOSECONDS);
return returnValue;
} catch (Exception exception) {
// Do not handle java.lang.Error
long durationInNanos = System.nanoTime() - start;
//调用失败,根据是否记录异常,行为不同
//调用顺序 CircuitBreakerStateMachine.onError ->CircuitBreakerState.handleThrowable
circuitBreaker.onError(durationInNanos, TimeUnit.NANOSECONDS, exception);
throw exception;
}
};
}
三:CircuitBreakerStateMachine状态机实现
上面提到状态已经创建好,但是状态之间是如何转换的,封装了CircuitBreakerStateMachine来实现,它实现了CircuitBreaker接口,实现的功能包括
- 实现状态转换机制
- 熔断机制和事件发布机制
- CircuitBreakerStateMachine提供了9种创建CircuitBreakerStateMachine实例的构造方法,如根据默认配置创建、根据自定义的配置创建等
- CircuitBreakerStateMachine提供了状态转换的公共方法stateTransition,其中利用AtomicReference来保证在状态转换过程中对CircuitBreakerState引用的原子性,
//状态转换公共逻辑方法
private void stateTransition(State newState,
UnaryOperator<CircuitBreakerState> newStateGenerator) {
//先获取当前状态,然后执行状态更新方法
CircuitBreakerState previousState = stateReference.getAndUpdate(currentState -> {
//获取 状态转换的枚举
StateTransition.transitionBetween(getName(), currentState.getState(), newState);
//更新为新状态
return newStateGenerator.apply(currentState);
});
//得到状态转换的枚举值,再查看是否设置了强制发布事件/允许发布事件,如果是,则发布状态转换事件
publishStateTransitionEvent(
StateTransition.transitionBetween(getName(), previousState.getState(), newState));
}
- CircuitBreakerStateMachine还提供了记录异常的实现:
private void handleThrowable(long duration, TimeUnit durationUnit, Throwable throwable) {
//判断请求调用抛出的异常是否需要记录,默认所有异常都需要记录
if (circuitBreakerConfig.getIgnoreExceptionPredicate().test(throwable)) {
//不需要记录异常
LOG.debug("CircuitBreaker '{}' ignored an exception:", name, throwable);
//(只有HalfOpenStat才有实现,将通过数+1,因为次异常不需要记录,忽略了)
releasePermission();
//发布忽略异常事件
publishCircuitIgnoredErrorEvent(name, duration, durationUnit, throwable);
} else if (circuitBreakerConfig.getRecordExceptionPredicate().test(throwable)) {
//需要记录异常
LOG.debug("CircuitBreaker '{}' recorded an exception as failure:", name, throwable);
//发布请求失败事件
publishCircuitErrorEvent(name, duration, durationUnit, throwable);
//调用当前状态CircuitBreakerState的onError()
stateReference.get().onError(duration, durationUnit, throwable);
} else {
LOG.debug("CircuitBreaker '{}' recorded an exception as success:", name, throwable);
//不是异常,就是正常请求,发布成功事件
publishSuccessEvent(duration, durationUnit);
//记录指标
stateReference.get().onSuccess(duration, durationUnit);
}
}
总结
CircuitBreaker采用装饰器模式,这也正是Resilience4j 框架的一大亮点,可以根据自己的需求,添加自己想要实现的功能,StateMachine主要负责CircuitBreakerState的转换