回顾之前文章:
1. 微服务熔断处理之断路器Resilience4j(一)
2. 微服务熔断处理之断路器Resilience4j-circuitbreaker组件(二)
两篇文章中介绍了 Resilience4j 的一些基本功能,详解Resilience4j-circuitbreaker组件源码流程,本文将继续梳理circuitbreaker组件中的熔断器度量指标以及熔断器事件发布;
1、CircuitBreakerMetrics(熔断器度量指标)
熔断器度量指标,熔断器在工作中,熔断相关实际数据,均存储在此。包括触发状态转换的请求调用失败率是如何计算的。相关联的类,如图:
CircuitBreaker.Metrics是一个度量指标接口,定义了一系列获取度量指标的方法,包括获取失败率的百分比、获取请求调用总数量,获取请求调用失败的数量、获取不允许请求调用通过的数量、获取设置的最大调用总数和获取请求调用成功的数量。
CircuitBreaker.Metrics 指标度量接口:
//度量指标接口,用于观察熔断器的各项指标
interface Metrics {
// 返回失败率百分比,如果调用数小于MINIMUM_NUMBER_OF_CALLS,返回-1
float getFailureRate();
//返回慢调用率百分比,如果调用数小于MINIMUM_NUMBER_OF_CALLS,返回-1
float getSlowCallRate();
//慢调用请求总数
int getNumberOfSlowCalls();
//慢调用成功总数
int getNumberOfSlowSuccessfulCalls();
//慢调用失败总数
int getNumberOfSlowFailedCalls();
//环形缓冲区的最大调用数
int getNumberOfBufferedCalls();
// 失败调用总数
int getNumberOfFailedCalls();
// 在打开状态下,返回当前不被允许请求调用的数量,在关闭和半开状态下,总返回0
long getNumberOfNotPermittedCalls();
//成功调用总数
int getNumberOfSuccessfulCalls();
}
CircuitBreakerMetrics类:
是CircuitBreaker.Metrics接口的实现类,具体内容就是实现了CircuitBreaker.Metrics 定义的方法:
//慢调用率
private float getSlowCallRate(Snapshot snapshot) {
int bufferedCalls = snapshot.getTotalNumberOfCalls();
if (bufferedCalls == 0 || bufferedCalls < minimumNumberOfCalls) {
return -1.0f;
}
return snapshot.getSlowCallRate();
}
//失败率
private float getFailureRate(Snapshot snapshot) {
//总共调用的次数
int bufferedCalls = snapshot.getTotalNumberOfCalls();
if (bufferedCalls == 0 || bufferedCalls < minimumNumberOfCalls) {
//ringBitSet中个数没有达到ringBufferSize大小,返回-1.0f,不计算失败率
return -1.0f;
}
//返回失败率:totalNumberOfFailedCalls * 100.0f / totalNumberOfCalls
return snapshot.getFailureRate();
}
onError()和onSuccess()方法是由状态机CircuitBreakerStateMachine的状态类中的onError()和onSuccess()方法调用的,检查是否达到了错误率阈值checkIfThresholdsExceeded() 进而调用状态机的状态转换方法 stateTransition():
/**
* Records a successful call and checks if the thresholds are exceeded.
* 成功调用时检查是否是慢调用,如果是慢调用,先发布慢调用事件,再统计慢调用率
* @return the result of the check
*/
public Result onSuccess(long duration, TimeUnit durationUnit) {
Snapshot snapshot;
if (durationUnit.toNanos(duration) > slowCallDurationThresholdInNanos) {
snapshot = metrics.record(duration, durationUnit, Outcome.SLOW_SUCCESS);
} else {
snapshot = metrics.record(duration, durationUnit, Outcome.SUCCESS);
}
return checkIfThresholdsExceeded(snapshot);
}
/**
* 失败时就会调用此方法,发布慢/错误事件,并检查是否达到阈值
* 1.先记录请求,即总请求次数,错误请求次数等+1
* 2. 计算失败率/慢调用率,是否达到阈值
*/
public Result onError(long duration, TimeUnit durationUnit) {
Snapshot snapshot;
if (durationUnit.toNanos(duration) > slowCallDurationThresholdInNanos) {
//慢调用,调用Core.Metrics 记录请求数
snapshot = metrics.record(duration, durationUnit, Outcome.SLOW_ERROR);
} else {
//错误调用,调用Core.Metrics 记录请求数
snapshot = metrics.record(duration, durationUnit, Outcome.ERROR);
}
return checkIfThresholdsExceeded(snapshot);
}
// 检查错误率/慢调用率是否达到阈值
private Result checkIfThresholdsExceeded(Snapshot snapshot) {
//获取失败率
float failureRateInPercentage = getFailureRate(snapshot);
if (failureRateInPercentage == -1) {
//小于缓冲大小,还未达到检查阈值
return Result.BELOW_MINIMUM_CALLS_THRESHOLD;
}
if (failureRateInPercentage >= failureRateThreshold) {
//超过阈值
return Result.ABOVE_THRESHOLDS;
}
//慢调用率
float slowCallsInPercentage = getSlowCallRate(snapshot);
if (slowCallsInPercentage >= slowCallRateThreshold) {
return Result.ABOVE_THRESHOLDS;
}
return Result.BELOW_THRESHOLDS;
}
还定义了检查是否达到阈值的枚举值:
enum Result {
BELOW_THRESHOLDS,
ABOVE_THRESHOLDS,
BELOW_MINIMUM_CALLS_THRESHOLD
}
2、CircuitBreakerEvent(熔断器事件)
2.1 事件机制框架
Resilience4j的事件机制是采用观察者模式设计的。Resilience4j事件关系图:
EventConsumer: 事件消费者,是个函数式接口,只有一个consumeEvent()方法,定义消费的具体行为:
//事件消费者接口(观察者)
@FunctionalInterface
public interface EventConsumer {
//用来处理T类型的事件
void consumeEvent(T event);
}
EventPublisher: 事件发布者,只有一个onEvent()方法,主要用来注册通用事件,即所有事件类型都会消费该event:
public interface EventPublisher {
//用于设置处理T事件的消费者
void onEvent(EventConsumer onEventConsumer);
}
EventProcessor: 主要用来注册消费者和调用消费者消费:
public class EventProcessor implements EventPublisher {
//用来存放通用事件消费者
List<EventConsumer<T>> onEventConsumers = new CopyOnWriteArrayList<>();
//用来存放定义的6种特定的CircuitBreakerEvent事件
//key:6种事件的类名,value:事件实例
ConcurrentMap<String, List<EventConsumer<T>>> eventConsumerMap = new ConcurrentHashMap<>();
private boolean consumerRegistered;
public EventProcessor() {
}
public boolean hasConsumers() {
return this.consumerRegistered;
}
//注册事件
//key:6种事件的类名,如CircuitBreakerOnSuccessEvent、CircuitBreakerOnErrorEvent等
//value:具体的消费者实例
//CircuitBreakerEventProcessor.onSuccess()等定义的6种事件调用
public synchronized void registerConsumer(String className, EventConsumer eventConsumer) {
this.consumerRegistered = true;
this.eventConsumerMap.compute(className, (k, consumers) -> {
if (consumers == null) {
List consumers = new ArrayList();
consumers.add(eventConsumer);
return consumers;
} else {
consumers.add(eventConsumer);
return consumers;
}
});
}
//调用消费者消费事件,返回true 已处理,false未处理
public boolean processEvent(E event) {
boolean consumed = false;
// 通用消费者消费事件
if (!this.onEventConsumers.isEmpty()) {
this.onEventConsumers.forEach((onEventConsumer) -> {
onEventConsumer.consumeEvent(event);
});
consumed = true;
}
// 特定消费者消费事件
if (!this.eventConsumerMap.isEmpty()) {
//*** 从注册的消费者中筛选符合类型的消费者
//即筛选key为指定事件的类名的消费者,如CircuitBreakerOnSuccessEvent
List<EventConsumer<T>> eventConsumers = (List)this.eventConsumerMap.get(event.getClass().getSimpleName());
if (eventConsumers != null && !eventConsumers.isEmpty()) {
eventConsumers.forEach((consumer) -> {
//***调用消费者消费事件
consumer.consumeEvent(event);
});
consumed = true;
}
}
return consumed;
}
//用来注册通用事件
public synchronized void onEvent(@Nullable EventConsumer onEventConsumer) {
this.consumerRegistered = true;
this.onEventConsumers.add(onEventConsumer);
}
}
消费注册实现原理:
以调用成功为例,在注册即往 eventConsumerMap = new ConcurrentHashMap()注册消费者时 this.registerConsumer(CircuitBreakerOnSuccessEvent.class.getSimpleName(), onSuccessEventConsumer),指定了key为“CircuitBreakerOnSuccessEvent”,消费时先创建CircuitBreakerOnSuccessEvent事件,消费时就会获取创建的该事件的类名,去map中筛选eventConsumers = this.eventConsumerMap .get(event.getClass().getSimpleName()); 这样就形成了一个闭环;
不同的行为对应不同的行为实现和不同的事件,这部分代码实现思维很值得学习;
消费注册实现梳理调用关系:
创建circuitBreaker后,就可以使用得到EventPublisher 从而调用 ——> onSuccess进行注册 circuitBreaker.getEventPublisher().onSuccess(event -> log.error(“消费成功”) ); ——>执行后端调用,成功获取信号量调用成功后,调用 ——>circuitBreaker.onSuccess()——>publishSuccessEvent()——>创建CircuitBreakerOnSuccessEvent事件 ——>CircuitBreakerEventProcessor.consumeEvent()——>EventProcessor.processEvent()消费事件;
2.2 CircuitBreaker的事件类型
CircuitBreaker一共定义了6种Event:
- CircuitBreakerOnErrorEvent: 请求调用失败时发布的事件
- CircuitBreakerOnSuccessEvent:请求调用成功时发布的事件
- CircuitBreakerOnStateTransitionEvent:熔断器状态转换时发布的事件
- CircuitBreakerOnResetEvent:熔断器重置时发布的事件
- CircuitBreakerOnIgnoredErrorEvent:当忽略的调用异常发生时发布的事件
- CircuitBreakerOnCallNotPermittedEvent:当请求不被允许调用时发布的事件
如果要使用事件,则必须注册事件使用者,如想在调用成功后执行某个操作,必须先注册CircuitBreakerOnSuccessEvent的消费者;
circuitBreaker.getEventPublisher()
.onSuccess(event -> logger.info("调用成功"));
如果想所有事件都触发,可以注册通用消费者:
circuitBreaker.getEventPublisher()
.onEvent(event -> logger.info("通用事件"));
3、熔断器模块总结
3.1 熔断器初始化时的状态:
一般创建熔断器的代码:
这2行代码产生了一系列的调用关系,如图:
这时熔断器的状态是关闭状态(ClosedState),度量指标实例及事件处理器实例都已经准备好。我们这时可以用CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics();这行代码实时的获取度量指标值。
3.2 熔断器状态转换
在这里,我们只分析熔断器从关闭状态转换到打开状态,其他状态之间的转换过程是一样的。
ClosedState ==> OpenState 状态的转换过程,如图:
熔断器通过decorateSupplier方法装饰请求调用的方法,如:
CircuitBreaker.decorateSupplier(circuitBreaker, helloWorldService::returnHelloWorld);
会发生如图所示的调用过程:
- 熔断器判断当前状态是否允许请求调用,关闭状态始终返回true。
- 执行请求调用方法
- 请求调用的结果成功或失败,熔断器最终会调用度量指标CircuitBreakerMetrics的onSuccess或onError方法返回请求调用失败率到ClosedState。ClosedState会在它的onSuccess或onError方法中判断请求失败率是否达到了设置的阈值,如果达到了阈值则调用状态机CircuitBreakerStateMachine的transitionToOpenState方法生成OpenState对象,同时把关闭状态的度量指标对象传给打开状态。然后熔断器把当前持有的状态更改为打开状态,完成了状态转换。