springcloud — 微服务熔断处理之断路器Resilience4j-circuitbreaker组件(三)

回顾之前文章:
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);

会发生如图所示的调用过程:

  1. 熔断器判断当前状态是否允许请求调用,关闭状态始终返回true。
  2. 执行请求调用方法
  3. 请求调用的结果成功或失败,熔断器最终会调用度量指标CircuitBreakerMetrics的onSuccess或onError方法返回请求调用失败率到ClosedState。ClosedState会在它的onSuccess或onError方法中判断请求失败率是否达到了设置的阈值,如果达到了阈值则调用状态机CircuitBreakerStateMachine的transitionToOpenState方法生成OpenState对象,同时把关闭状态的度量指标对象传给打开状态。然后熔断器把当前持有的状态更改为打开状态,完成了状态转换。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RachelHwang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值