resilience4j之CircuitBreaker熔断器——CircuitBreakerStateMachine状态机

文章目录

  • 一:CircuitBreakerState状态的实现
  • 二:CircuitBreaker 熔断器
  • 三:CircuitBreakerStateMachine状态机实现
  • 总结

resilience4j之CircuitBreaker熔断器——CircuitBreakerStateMachine状态机_第1张图片

一:CircuitBreakerState状态的实现

CircuitBreaker有5种状态,把这5种状态的公共属性和行为抽象到CircuitBreakerState,然后5种状态ClosedState、OpenState、DisabledState、ForcedOpenState、HalfOpenState分别去实现各自的行为
resilience4j之CircuitBreaker熔断器——CircuitBreakerStateMachine状态机_第2张图片
其中公共行为有:

//把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 熔断器

  1. 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;
        }
  1. 声明了Metrics度量接口,由CircuitBreakerMetrics实现,在后面文章会讲到
  2. 声明了EventPublisher 事件处理器接口,继承core.EventPublisher,由CircuitBreakerStateMachine.CircuitBreakerEventProcessor实现,用于向EventProcessor中注册处理六种事件的EventConsumer,也用于处理事件,在后面文章会讲到
    resilience4j之CircuitBreaker熔断器——CircuitBreakerStateMachine状态机_第3张图片
  3. 提供了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 tags) {
        return new CircuitBreakerStateMachine(name, circuitBreakerConfig, tags);
    }

     //直接创建名为name,指定配置的熔断器,使用java的supplier
    static CircuitBreaker of(String name,
        Supplier circuitBreakerConfigSupplier) {
        return new CircuitBreakerStateMachine(name, circuitBreakerConfigSupplier);
    }

    static CircuitBreaker of(String name,
        Supplier circuitBreakerConfigSupplier,
        io.vavr.collection.Map tags) {
        return new CircuitBreakerStateMachine(name, circuitBreakerConfigSupplier, tags);
    }
  1. 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  Supplier decorateSupplier(CircuitBreaker circuitBreaker, Supplier 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接口,实现的功能包括

  • 实现状态转换机制
  • 熔断机制和事件发布机制
  1. CircuitBreakerStateMachine提供了9种创建CircuitBreakerStateMachine实例的构造方法,如根据默认配置创建、根据自定义的配置创建等
  2. CircuitBreakerStateMachine提供了状态转换的公共方法stateTransition,其中利用AtomicReference来保证在状态转换过程中对CircuitBreakerState引用的原子性,
    //状态转换公共逻辑方法
    private void stateTransition(State newState,
        UnaryOperator newStateGenerator) {
        //先获取当前状态,然后执行状态更新方法
        CircuitBreakerState previousState = stateReference.getAndUpdate(currentState -> {
            //获取 状态转换的枚举
            StateTransition.transitionBetween(getName(), currentState.getState(), newState);
            //更新为新状态
            return newStateGenerator.apply(currentState);
        });
        //得到状态转换的枚举值,再查看是否设置了强制发布事件/允许发布事件,如果是,则发布状态转换事件
        publishStateTransitionEvent(
            StateTransition.transitionBetween(getName(), previousState.getState(), newState));
    }
  1. 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的转换

你可能感兴趣的:(resilience4j)