Soul-源码阅读21-rateLimiter插件

前言

  • 采用redis令牌桶算法进行限流。
  • 限流插件是网关对流量管控、限制核心的实现。
  • 流量配置可以到接口级别、参数级别。

使用rateLimiter

  • 启动soul-admin,在 soul-admin–> 插件管理–> rate_limiter 将其设置为开启,redis部署模式默认为单机,如果是哨兵(sentinel),集群(cluster)等多节点的,在URL中的配置,请对每个实列使用 ; 分割. 如 192.168.1.1:6379;192.168.1.2:6379。。
    在这里插入图片描述

  • 在boostrap的pom.xml引入ratelimiter依赖

    <!-- soul ratelimiter plugin start-->
    <dependency>
        <groupId>org.dromara</groupId>
        <artifactId>soul-spring-boot-starter-plugin-ratelimiter</artifactId>
        <version>${project.version}</version>
    </dependency>
    <!-- soul ratelimiter plugin end-->
    
  • 启动soul-examples-http 服务

  • 在 admin 后台选择 rateLimiter 插件,添加选择器

在这里插入图片描述

  • 添加规则,设置例子服务的url地址、桶容量为10和速率为5。

在这里插入图片描述

  • 容量是令牌数,用户在一秒内执行的最大请求数。速率是令牌桶的填充速率,允许用户每秒执行多少请求,而丢弃任何请求。

  • 测试接口,比如用postman测试 ,设置并发数50,延迟为0,确认调第11次开始,接口返回异常。

源码分析

  • RateLimiterPlugin#doExecute,判断请求是否允许通过,允许就执行下一个。

    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#redisScript 获取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;
    }
    
  • 用 lua 脚本来保证操作的原子性的,看脚本大概是最后返回一个allowed_num,1表示通过,0不通过。

  • 会通过 lua 脚本在 redis 创建两个 key,通过1个请求减少一个容量,然后按照上面设置的rate填充速率(如:令牌桶10,速率是5),请求太快,就不允许通过了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值