一、背景
Soul 网关对于流量的限流提供了三种插件
- RateLimiter 依赖 Redis 做的令牌桶
- Netfix Hystrix 基于RxJava实现,已停止更新好多年了,可能也是成熟稳定没什么好更新了,更多的可能是 Netfix 已经拥抱下一代分布式服务架构了
- Sentinel 阿里开源的
- Resilience4J Hystrix停更之后,Netflix官方推荐移步至resilience4j,它是一个轻量、易用、可组装的高可用框架,支持熔断、高频控制、隔离、限流、限时、重试等多种高可用机制。
网上找的对比图
感觉学 Soul 网关,作为分布式服务的入口,要把周围技术都学一遍。今天看了小马哥的公开课中提到 MicroProfile microprofile.io/ ,原来在分布式的服务的世界不仅仅只有 Spring 或者 Service Mech。MicroProfile 制定了一些类微服务规范,有 IBM、Red Hat 背书,且已经有 Red Hat 支持的开源社区实现项目。这里有一篇介绍文章 my.oschina.net/u/4567873/b…
这里也有文档 download.eclipse.org/microprofil…
扯远了,回到正题。
二、开始学习
困了,就不演示了,直接看插件代码了~~
1、RateLimiter
protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
final String handle = rule.getHandle();
final RateLimiterHandle limiterHandle = GsonUtils.getInstance().fromJson(handle, RateLimiterHandle.class);
return redisRateLimiter.isAllowed(rule.getId(), limiterHandle.getReplenishRate(), limiterHandle.getBurstCapacity())
.flatMap(response -> {
if (!response.isAllowed()) {
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
Object error = SoulResultWrap.error(SoulResultEnum.TOO_MANY_REQUESTS.getCode(), SoulResultEnum.TOO_MANY_REQUESTS.getMsg(), null);
return WebFluxResultUtils.result(exchange, error);
}
return chain.execute(exchange);
});
}
RedisRateLimiter#isAllowed 限流方法
public Mono<RateLimiterResponse> isAllowed(final String id, final double replenishRate, final double burstCapacity) {
if (!this.initialized.get()) {
throw new IllegalStateException("RedisRateLimiter is not initialized");
}
List<String> keys = getKeys(id);
List<String> scriptArgs = Arrays.asList(replenishRate + "", burstCapacity + "", Instant.now().getEpochSecond() + "", "1");
Flux<List<Long>> resultFlux = Singleton.INST.get(ReactiveRedisTemplate.class).execute(this.script, keys, scriptArgs);
return resultFlux.onErrorResume(throwable -> Flux.just(Arrays.asList(1L, -1L)))
.reduce(new ArrayList<Long>(), (longs, l) -> {
longs.addAll(l);
return longs;
}).map(results -> {
boolean allowed = results.get(0) == 1L;
Long tokensLeft = results.get(1);
RateLimiterResponse rateLimiterResponse = new RateLimiterResponse(allowed, tokensLeft);
log.info("RateLimiter response:{}", rateLimiterResponse.toString());
return rateLimiterResponse;
}).doOnError(throwable -> log.error("Error determining if user allowed from redis:{}", throwable.getMessage()));
}
可以看到很超前 Redis 操作都是 Reactive 模式的,具体的 lua 脚本
private RedisScript<List<Long>> redisScript() {
DefaultRedisScript redisScript = new DefaultRedisScript<>();
redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("/META-INF/scripts/request_rate_limiter.lua")));
redisScript.setResultType(List.class);
return redisScript;
}
在 /META-INF/scripts/request_rate_limiter.lua 中,反正我是看不懂。
2、Hystrix
不贴代码了,安慰自己 hystrix 四年没更新了,RxJava 也没有 ProjectReactor 火,而且 Netfix 官方都让你移步Resilience4J~_~
3、Sentinel
这个总逃不过吧,先放弃了。
4、Resilience4J
Resilience4j是受到Netflix Hystrix的启发,为Java8和函数式编程所设计的轻量级容错框架。整个框架只是使用了Varr的库,不需要引入其他的外部依赖。与此相比,Netflix Hystrix对Archaius具有编译依赖,而Archaius需要更多的外部依赖,例如Guava和Apache Commons Configuration。
最后在推荐一篇介绍 Sentinel 的文章 my.oschina.net/xiaominmin/…
总之,人生苦短,这么多限流工具,选择 Sentinel 学吧,实在精力旺盛我在看看 Redis 限流。