(十四)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的配置规则详解(摘自官网):
- 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插件包的信息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怎么使用