当前位置: 首页 > 工具软件 > JPlugin > 使用案例 >

Soul网关源码学习(16)- Resilience4JPlugin分析

夔光霁
2023-12-01

前言

在上一篇文章《Soul网关源码学习(15)- HystrixPlugin 分析》中,我们分析了 soul 集成 hystrix的原理,这一章我们再来分析一下 Resilience4J 到底是如果通过 Resilience4JPlugin 集成到 soul 里面的。

Resilience4J

Resilience4j是受到Netflix Hystrix的启发,为Java8和函数式编程所设计的轻量级容错框架。整个框架只是使用了Varr的库,不需要引入其他的外部依赖。与此相比,Netflix Hystrix对Archaius具有编译依赖,而Archaius需要更多的外部依赖,例如Guava和Apache Commons Configuration。

Resilience4j提供了提供了一组高阶函数(装饰器),包括断路器,限流器,重试机制,隔离机制。你可以使用其中的一个或多个装饰器对函数式接口,lambda表达式或方法引用进行装饰。这么做的优点是你可以选择所需要的装饰器进行装饰。

在使用Resilience4j的过程中,不需要引入所有的依赖,只引入需要的依赖即可。

Resilience4JPlugin

Resilience4JPlugin 是继承于模板类 AbstractSoulPlugin,所以 doExecutor 是其执行真正功能逻辑的代码:

@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;
    Resilience4JHandle resilience4JHandle = GsonUtils.getGson().fromJson(rule.getHandle(), Resilience4JHandle.class);
    //如果开启熔断配置
    if (resilience4JHandle.getCircuitEnable() == 1) {
        return combined(exchange, chain, rule);
    }
    //如果不开启熔断就只使用 Resilience4J 的限流组件
    return rateLimiter(exchange, chain, rule);
}

上面代码主要有两点:

  • 如果控制台开启熔断配置,则打创建熔断和限流的组合控件。
  • 否则只使用限流组件

combined 方法:

private Mono<Void> combined(final ServerWebExchange exchange, final SoulPluginChain chain, final RuleData rule) {
	//创建Resilience4J相关配置
    Resilience4JConf conf = Resilience4JBuilder.build(rule);
    return combinedExecutor.run(
            //插件链后续执行
            chain.execute(exchange)
                    .doOnSuccess(v -> {
                    	...
                    }),
            //降级处理
            fallback(combinedExecutor, exchange, conf.getFallBackUri()), conf);
}

combinedExecutor 是 soul 自己封装的执行器,下面是器 run 方法:

@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());
        //Resilience4J 函数是支持多组件链式调用的
        //首先执行熔断器
        Mono<T> to = run.transformDeferred(CircuitBreakerOperator.of(circuitBreaker))
                //再执行限流
                .transformDeferred(RateLimiterOperator.of(rateLimiter))
                ...
        if (fallback != null) {
            //降级处理
            to = to.onErrorResume(fallback);
        }
        return to;
    }

这是真正使用 Resilience4J 功能的核心代码:创建 Resilience4J 熔断器和限流器,并且通过函数式链式调用把 Soul 后续的执行任务包装进去。
接下来我们在看一下 Resilience4J 不同修饰器配置创建的地方,回到上面 combined 方法,我们很容易就知道了 Resilience4JBuilder 就是我们要找的类:

	// Resilience4JBuilder build 方法,省略了部分设置代码
   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()
                    //熔断失败判定:所有 Throwable 和 Throwable 都会被判定失败
                    .recordExceptions(Throwable.class, Throwable.class)
                    ...
                    //断路器在半开状态下允许通过的调用次数。
                    .permittedNumberOfCallsInHalfOpenState(handle.getPermittedNumberOfCallsInHalfOpenState()).build();
        }
        //限时组件配置
        TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom()
                //配置任务执行超时限制
                .timeoutDuration(Duration.ofSeconds(handle.getTimeoutDuration() / 1000)).build();
        //限流组件配置
        RateLimiterConfig rateLimiterConfig = RateLimiterConfig.custom()
        		...
                //限流器每隔limitRefreshPeriod刷新一次,将允许处理的最大请求数量重置为limitForPeriod
                .limitRefreshPeriod(Duration.ofNanos(handle.getLimitRefreshPeriod() * 1000000)).build();
        return new Resilience4JConf(Resilience4JHandler.getResourceName(ruleData), handle.getFallbackUri(), rateLimiterConfig, timeLimiterConfig, circuitBreakerConfig);
    }

到这里我们小结一下 Resilience4JPlugin 组合熔断和限流的流程:

  • doExecute 方法中调用 combined 方法。
  • combined 通过 Resilience4JBuilder#build 方法创建熔断器、限流器、限时器的配置。
  • combined 方法再通过 combinedExecutor 对象的run方法真正使用 Resilience4J 的功能。

分析完熔断和限流的组合使用后,那后面的单一限流的实现应该就更加简单了,过程大同小异只是少了熔断器而已,其方法入口是 rateLimiter,有兴趣的小伙伴可以自己去跟踪一下,这里就不重复分析了。

总结

到这里 Resilience4J 的集成原理也分析完了,相对于上一篇 Hystrix 的集成分析,这篇明显简单了许多。这可能是得益于 Resilience4J 简单易用的 API 设计(组合功能 + 链式调用)。后面熔断框架集成的源码分析就只剩下最后关于 sentinel 的一篇了,这个后续会继续带来的。

 类似资料: