Soul网关第13天:体验限流插件RateLimiter、Hystrix、Sentinel、Resilience4J

552 阅读2分钟

一、背景

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 限流。