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


在这里插入图片描述

一: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 熔断器

  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,也用于处理事件,在后面文章会讲到
    在这里插入图片描述
  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<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);
    }
  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 <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接口,实现的功能包括

  • 实现状态转换机制
  • 熔断机制和事件发布机制
  1. CircuitBreakerStateMachine提供了9种创建CircuitBreakerStateMachine实例的构造方法,如根据默认配置创建、根据自定义的配置创建等
  2. 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));
    }
  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的转换

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Resilience4j 是一个用于构建弹性和容错性应用程序的轻量级库,其中包括熔断(Circuit Breaker)功能。下面是 Resilience4j 熔断的简单使用方法: 1. 添加 Maven 依赖:在项目的 pom.xml 文件中添加以下 Maven 依赖: ```xml <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-circuitbreaker</artifactId> <version>1.7.0</version> </dependency> ``` 2. 创建熔断实例:使用 CircuitBreakerRegistry 创建一个熔断实例。 ```java CircuitBreakerConfig config = CircuitBreakerConfig.custom() .failureRateThreshold(50) // 失败率阈值 .waitDurationInOpenState(Duration.ofMillis(1000)) // 熔断打开后等待时间 .ringBufferSizeInHalfOpenState(2) // 半开状态下环形缓冲区大小 .ringBufferSizeInClosedState(2) // 关闭状态下环形缓冲区大小 .build(); CircuitBreakerRegistry registry = CircuitBreakerRegistry.of(config); CircuitBreaker circuitBreaker = registry.circuitBreaker("myCircuitBreaker"); ``` 3. 包装方法调用:使用熔断包装需要进行容错处理的方法调用。 ```java CircuitBreaker.decorateCheckedSupplier(circuitBreaker, () -> { // 调用需要容错处理的方法 return myService.doSomething(); }); ``` 4. 处理熔断状态:根据熔断状态进行相应处理。 ```java if (circuitBreaker.getState() == CircuitBreaker.State.OPEN) { // 熔断打开时的处理逻辑 // 例如,返回一个默认值或者抛出一个自定义异常 } else { // 熔断关闭或半开时的处理逻辑 // 例如,正常执行业务逻辑 } ``` 上述步骤中,你可以根据实际需求配置熔断的参数,如失败率阈值、等待时间、环形缓冲区大小等。通过包装方法调用,当方法调用失败或达到一定条件时,熔断将会打开,并执行相应的容错逻辑。你可以根据熔断状态来处理不同的情况。 注意:上述代码片段仅为示例,你需要根据自己的业务需求进行适当的调整和配置。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值