soul从入门到放弃10--浅入浅出resilience4j插件

一、Soul-Admin的相关配置

  • 开启resilience4j

运行Soul-admin,进入管理界面:系统管理 --> 插件管理 --> resilience4j ,点击编辑,把它开启

  • 配置选择器与规则

选择器参照divide的匹配方式,让符合条件的http的请求,能被捕获到

image.png

规则配置,配置项名称官网的文档对应不太一样,一下按照自己的理解解释下:

image.png
  • token filling period (ms):刷新令牌的时间间隔,单位ms,默认值:500。

  • token filling number:每次刷新令牌的数量,默认值:50。

  • control behavior timeout (ms):熔断服务,对外停止服务持续时间,单位ms

  • circuit enable:是否开启熔断,0:关闭,1:开启,默认值:0。

  • circuit timeout (ms):熔断超时时间,请求服务响应超过此时间,则触发熔断,单位ms,默认值:30000。

  • fallback uri:降级处理的uri。

  • sliding window size:滑动窗口大小,默认值:100。

  • sliding window type:滑动窗口类型,0:基于计数,1:基于时间,默认值:0。

  • enabled error minimum calculation threshold: 开启熔断的最小请求数,超过这个请求数才开启熔断统计,默认值:100。

  • degrade opening duration:熔断器开启持续时间,单位ms,默认值:10
    此配置请一定大于或等于1000,小心有坑


    image.png
  • half open threshold:半开状态下的环形缓冲区大小,必须达到此数量才会计算失败率,默认值:10。

  • degrade failure rate错误率百分比,达到这个阈值,熔断器才会开启,默认值50。

二、Soul-Bootstrap配置启动

 
 
org.dromara 
soul-spring-boot-starter-plugin-resilience4j ${last.version} 
 

三、测试

真正测试之前要明确一下关于熔断状态项

三个一般性状态

  • CLOSED:关闭状态,放过所有请求,记录请求状态。
  • OPEN:打开,异常请求达到阀值数量时,开启熔断,拒绝所有请求。
  • HALF_OPEN:半开,放开一定数量的请求,重新计算错误率。

两个待定状态

  • DISABLED:禁用
  • FORCED_OPEN:强开

一图胜千言

image.png

因为熔断需要达到一定的阈值才能触发,所以跑一个wrk,让流量压起来

wrk -t4 -c32 -d10s http://localhost:9195/http/test/findByUserId?userId=2

启动测试一下::http://localhost:9195/http/test/findByUserId?userId=2

此处有一点小问题:明显看出此时熔断已经起作用了,但是配置了fallback uri,转发请求失败,需要调试一下

{
    "code": 500,
    "message": "Internal Server Error",
    "data": "404 NOT_FOUND \"No matching handler\""
}

熔断周期结束后,流量降下来了,同时单个响应时间也降下来时,就返回正常了

{
    "userId": "2",
    "userName": "hello world"
}

四、源码分析

RateLimiterPlugin是继承了AbstractSoulPlugin,所以会先走AbstractSoulPlugin中路由匹配的相关逻辑,之后再走RateLimiterPlugin的doExcute限流的处理逻辑,以上都其他插件的流程是类似的。

  # AbstractSoulPlugin
    // 首先进行路由匹配
    public Mono execute(final ServerWebExchange exchange, final SoulPluginChain chain) {
        String pluginName = named(); final PluginData pluginData = BaseDataCache.getInstance().obtainPluginData(pluginName); if (pluginData != null && pluginData.getEnabled()) {
        // some code
            return doExecute(exchange, chain, selectorData, rule);
        }
        return chain.execute(exchange);
    }

进入RateLimiterPlugin看看具体作了什么工作

 # RateLimiterPlugin
    // 匹配完成后走限流的逻辑
    protected Mono doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
        final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);
        assert soulContext != null;
        // 此处soul-admin配置规则转json转成对象,注意格式,不能瞎整
        Resilience4JHandle resilience4JHandle = GsonUtils.getGson().fromJson(rule.getHandle(), Resilience4JHandle.class);
        // 只有Circle enable不等于1时,走限流的逻辑,其他都是熔断
        if (resilience4JHandle.getCircuitEnable() == 1) {
            return combined(exchange, chain, rule);
        }
        return rateLimiter(exchange, chain, rule);
    }

// 给CombinedExecutor父类Executor的高阶函数run,传递设置熔断中各种情况的处理方式,以及生成熔断器等方法处理方式

private Mono combined(final ServerWebExchange exchange, final SoulPluginChain chain, final RuleData rule) {
    Resilience4JConf conf = Resilience4JBuilder.build(rule);
    return combinedExecutor.run(
      // chain.execute(exchange)作为Mono类型参数,传递到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);
                }
                // Resilience4JPlugin的fallback,用转发熔断请求
            }), fallback(combinedExecutor, exchange, conf.getFallBackUri()), conf);
}

进入combinedExecutor,再探究竟,主要是以 Webflux 中Mono对象,对请求的各种处理方式设置,以及熔断转发的触发

if (fallback != null) {
    to = to.onErrorResume(fallback);
}

总结:

1.这个插件熔断转发没有测试成功,目测应该是响应式编程的知识欠缺

2.代码写不好需要重构,文章也一样

3.日拱一卒

你可能感兴趣的:(soul从入门到放弃10--浅入浅出resilience4j插件)