(十四)soul源码的Resilience4j体验和原理

目标

  • 什么是Resilience4j
  • sould的Resilience4j体验

什么是Resilience4j

  • Resilience4J是我们Spring Cloud G版本 推荐的容错方案,它是一个轻量级的容错库
  • 借鉴了Hystrix而设计,并且采用JDK8 这个函数式编程,即lambda表达式
  • 相比之下, Netflix Hystrix 对Archaius 具有编译依赖性,Resilience4j你无需引用全部依赖,可以根据自己需要的功能引用相关的模块即可
    Hystrix很早就不更新了,Spring官方已经出现了Netflix Hystrix的替换方案,即Resilence4J
  • Resilience4J 提供了一系列增强微服务的可用性功能:
  • 断路器 CircuitBreaker
  • 限流 RateLimiter
  • 基于信号量的隔离
  • 缓存
  • 限时 Timelimiter
  • 请求重启 Retry
  • 官方提供的依赖包
<dependency>
           <groupId>io.github.resilience4j</groupId>
           <artifactId>resilience4j-circuitbreaker</artifactId>
           <version>${resilience.version}</version>
    </dependency>

sould的Resilience4j体验

  • 首先在admin控制台的插件管理开始Resilience4j
  • 在网关添加依赖
<dependency>
           <groupId>org.dromara</groupId>
           <artifactId>soul-spring-boot-starter-plugin-ratelimiter</artifactId>
           <version>${project.version}</version>
       </dependency>
  • 启动一个admin,一个soul-bootstrap,一个soulTtestHttp。三个服务
  • 在admin控制台找到插件列表的Resilience4j,自定义配置,如下图,
  • resilience4j限流的缺陷 resilience4j原理_默认值

阻塞问题了,Resilience4j和官网提供的文档配置属性不一致,一些数据对不上,

  • Resilience4j的配置规则详解(摘自官网):
  • timeoutDurationRate:等待获取令牌的超时时间,单位ms,默认值:5000。
  • limitRefreshPeriod:刷新令牌的时间间隔,单位ms,默认值:500。
  • limitForPeriod:每次刷新令牌的数量,默认值:50。
  • circuitEnable:是否开启熔断,0:关闭,1:开启,默认值:0。
  • timeoutDuration:熔断超时时间,单位ms,默认值:30000。
  • fallbackUri:降级处理的uri。
  • slidingWindowSize:滑动窗口大小,默认值:100。
  • slidingWindowType:滑动窗口类型,0:基于计数,1:基于时间,默认值:0。
  • minimumNumberOfCalls:开启熔断的最小请求数,超过这个请求数才开启熔断统计,默认值:100。
  • waitIntervalFunctionInOpenState:熔断器开启持续时间,单位ms,默认值:10。
  • permittedNumberOfCallsInHalfOpenState:半开状态下的环形缓冲区大小,必须达到此数量才会计算失败率,默认值:10。
  • failureRateThreshold:错误率百分比,达到这个阈值,熔断器才会开启,默认值50。
  • automaticTransitionFromOpenToHalfOpenEnabled:是否自动从open状态转换为half-open状态,,true:是,false:否,默认值:false。
当我的Resilience4j配置如上图时 ,请求服务,会调用服务fallback接口

resilience4j限流的缺陷 resilience4j原理_默认值_02

Resilience4J插件包的信息

resilience4j限流的缺陷 resilience4j原理_默认值_03

Resilience4JPlugin核心源码

@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);
       }
       return rateLimiter(exchange, chain, rule);
   }

   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));
   }

   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);
   }

总结

  • 还需要补充Resilience4j怎么使用