soul 源码分析 —— 插件解析之resilience4j插件

作用:

resilience4j是用来进行限流和熔断的。

引入:

<dependency>
    <groupId>org.dromara</groupId>
    <artifactId>soul-spring-boot-starter-plugin-resilience4j</artifactId>
    <version>${project.version}</version>
</dependency>

熔断器配置:
后台启用resilience4j插件
在这里插入图片描述
在这里插入图片描述

control behavior timeout (ms)(timeoutDurationRate):等待获取令牌的超时时间,单位ms,默认值:5000。
token filling period (ms)(limitRefreshPeriod):刷新令牌的时间间隔,单位ms,默认值:500。
token filling number(limitForPeriod):每次刷新令牌的数量,默认值:50。
circuit enable(circuitEnable):是否开启熔断,0:关闭,1:开启,默认值:0。
circuit timeout (ms)(timeoutDuration):熔断超时时间,单位ms,默认值:30000。
fallback uri(fallbackUri):降级处理的uri。
sliding window size(slidingWindowSize):滑动窗口大小,默认值:100。
sliding window type(slidingWindowType):滑动窗口类型,0:基于计数,1:基于时间,默认值:0。
enabled error minimum calculation threshold(minimumNumberOfCalls):开启熔断的最小请求数,超过这个请求数才开启熔断统计,默认值:100。
degrade opening duration(waitIntervalFunctionInOpenState):熔断器开启持续时间,单位ms,默认值:10。
half open threshold(permittedNumberOfCallsInHalfOpenState):半开状态下的环形缓冲区大小,必须达到此数量才会计算失败率,默认值:10。
degrade failure rate(failureRateThreshold):错误率百分比,达到这个阈值,熔断器才会开启,默认值50。
automaticTransitionFromOpenToHalfOpenEnabled:是否自动从open状态转换为half-open状态,,true:是,false:否,默认值:false。

源码解析

进入到Resilience4JPlugindoExecute方法:

 @Override
    protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
        final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);
        assert soulContext != null;
        // 将resilience4j的rule配置转为Resilience4JHandle对象
        Resilience4JHandle resilience4JHandle = GsonUtils.getGson().fromJson(rule.getHandle(), Resilience4JHandle.class);
        // 如果开启断路器,执行combined方法
        if (resilience4JHandle.getCircuitEnable() == 1) {
            return combined(exchange, chain, rule);
        }
        // 如果不开启断路器,执行rateLimiter方法
        return rateLimiter(exchange, chain, rule);
    }

1)将后台配置的断路器规则转为Resilience4JHandle对象

2)判断断路器是否开启:

  • 开启,执行combined方法(多种操作:熔断、限流)
  • 未开启,执行rateLimiter方法(限流)

熔断限流的配置类

public class Resilience4JBuilder {

    /**
     * build.
     *
     * @param ruleData the ruleData
     * @return Resilience4JConf
     */
    public static Resilience4JConf build(final RuleData ruleData) {
        Resilience4JHandle handle = GsonUtils.getGson().fromJson(ruleData.getHandle(), Resilience4JHandle.class);
        CircuitBreakerConfig circuitBreakerConfig = null;
        if (handle.getCircuitEnable() == 1) {
            // 熔断配置类
            circuitBreakerConfig = CircuitBreakerConfig.custom()
                    // 请求调用失败,存储异常记录的集合
                    .recordExceptions(Throwable.class, Exception.class)
                    // 熔断器打开的失败阈值或半开状态使用的同一个失败率阈值
                    .failureRateThreshold(handle.getFailureRateThreshold())
                    // 是否自动从打开到半开,当waitDurationInOpenState时间一过,是否自动从OPEN切换到HALF_OPEN
                    // true:waitDurationInOpenState到期后open自动变为half_open
                    // false: 得等到再有请求后状态才会变为half_open,否则即使waitDurationInOpenState到期状态依然是open
                    .automaticTransitionFromOpenToHalfOpenEnabled(handle.getAutomaticTransitionFromOpenToHalfOpenEnabled())
                    // 滑动窗口类型,默认为基于计数的 COUNT_BASED
                    .slidingWindow(handle.getSlidingWindowSize(), handle.getMinimumNumberOfCalls(),
                            handle.getSlidingWindowType() == 0
                                    ? CircuitBreakerConfig.SlidingWindowType.COUNT_BASED
                                    : CircuitBreakerConfig.SlidingWindowType.TIME_BASED).waitIntervalFunctionInOpenState(IntervalFunction
                            .of(Duration.ofSeconds(handle.getWaitIntervalFunctionInOpenState() / 1000)))
                    // 熔断器半开时的缓冲区大小,会限制线程的并发量(只允许ringBufferSizeInHalfOpenState个并发),
                    // 例如缓冲区为10则每次只会允许10个请求调用后端服务
                    // 之所以能限制并发,CircuitBreakerStateMachine使用了AtomicInteger:this.permittedNumberOfCalls = new AtomicInteger(permittedNumberOfCallsInHalfOpenState);
                    .permittedNumberOfCallsInHalfOpenState(handle.getPermittedNumberOfCallsInHalfOpenState()).build();
        }

        // 超时配置
        TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom()
                .timeoutDuration(Duration.ofSeconds(handle.getTimeoutDuration() / 1000)).build();

        // 限流器配置
        RateLimiterConfig rateLimiterConfig = RateLimiterConfig.custom()
                // 周期内允许通过的请求数量。      默认:50
                .limitForPeriod(handle.getLimitForPeriod())
                // 获取授权操作的超时时间。 默认:5秒
                .timeoutDuration(Duration.ofSeconds(handle.getTimeoutDurationRate() / 1000))
                // 限流周期时长。       默认:500纳秒
                .limitRefreshPeriod(Duration.ofNanos(handle.getLimitRefreshPeriod() * 1000000)).build();

        return new Resilience4JConf(Resilience4JHandler.getResourceName(ruleData), handle.getFallbackUri(), rateLimiterConfig, timeLimiterConfig, circuitBreakerConfig);
    }
}

circuitBreakerConfig:熔断配置类

TimeLimiterConfig:超时配置

RateLimiterConfig:限流器配置

rateLimiter方法

private Mono<Void> rateLimiter(final ServerWebExchange exchange, final SoulPluginChain chain, final RuleData rule) {
        return ratelimiterExecutor.run(
                chain.execute(exchange), fallback(ratelimiterExecutor, exchange, null), Resilience4JBuilder.build(rule))
                .onErrorResume(throwable -> ratelimiterExecutor.withoutFallback(exchange, throwable));
}

// 限流类
public class RateLimiterExecutor implements Executor {

    @Override
    public <T> Mono<T> run(final Mono<T> toRun, final Function<Throwable, Mono<T>> fallback, final Resilience4JConf conf) {
        // 通过限流配置,创建限流类
        RateLimiter rateLimiter = Resilience4JRegistryFactory.rateLimiter(conf.getId(), conf.getRateLimiterConfig());
        Mono<T> to = toRun.transformDeferred(RateLimiterOperator.of(rateLimiter));
        if (fallback != null) {
            return to.onErrorResume(fallback);
        }
        return to;
    }
}

通过 ratelimiterExecutor的run方法进行限流的一些处理,以及错误处理onErrorResume

combined方法

private Mono<Void> combined(final ServerWebExchange exchange, final SoulPluginChain chain, final RuleData rule) {
        Resilience4JConf conf = Resilience4JBuilder.build(rule);
        return combinedExecutor.run(
                chain.execute(exchange).doOnSuccess(v -> {
                    if (exchange.getResponse().getStatusCode() != HttpStatus.OK) {
                        HttpStatus status = exchange.getResponse().getStatusCode();
                        exchange.getResponse().setStatusCode(null);
                        throw new CircuitBreakerStatusCodeException(status);
                    }
                }), fallback(combinedExecutor, exchange, conf.getFallBackUri()), conf);
    }

public class CombinedExecutor implements Executor {

    @Override
    public <T> Mono<T> run(final Mono<T> run, final Function<Throwable, Mono<T>> fallback, final Resilience4JConf resilience4JConf) {
        // 限流类
        RateLimiter rateLimiter = Resilience4JRegistryFactory.rateLimiter(resilience4JConf.getId(), resilience4JConf.getRateLimiterConfig());
        // 断路器类
        CircuitBreaker circuitBreaker = Resilience4JRegistryFactory.circuitBreaker(resilience4JConf.getId(), resilience4JConf.getCircuitBreakerConfig());
        // CircuitBreakerOperator.of(circuitBreaker):返回一个CircuitBreakerOperator的Publisher
        Mono<T> to = run.transformDeferred(CircuitBreakerOperator.of(circuitBreaker))
                // RateLimiterOperator.of(rateLimiter):返回一个RateLimiterOperator的Publisher
                .transformDeferred(RateLimiterOperator.of(rateLimiter))
                // 设置超时时间
                .timeout(resilience4JConf.getTimeLimiterConfig().getTimeoutDuration())
                // 错误处理
                .doOnError(TimeoutException.class, t -> circuitBreaker.onError(
                        resilience4JConf.getTimeLimiterConfig().getTimeoutDuration().toMillis(),
                        TimeUnit.MILLISECONDS,
                        t));
        if (fallback != null) {
            to = to.onErrorResume(fallback);
        }
        return to;
    }
}

通过 combinedExecutor的run方法进行断路器的一些处理

验证

正常请求:
在这里插入图片描述
熔断:
在这里插入图片描述
在这里插入图片描述
过一段时间请求,又恢复正常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值