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

回顾之前文章:微服务熔断处理之断路器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的值(借助子类的各自实现来化解状态转换的复杂逻辑),同时发布一些事件。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

RachelHwang

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

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

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

打赏作者

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

抵扣说明:

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

余额充值