spring boot (demo) Guava RateLimiter客户端限流

Guava官方文档-RateLimiter类

RateLimiter 从概念上来讲,速率限制器会在可配置的速率下分配许可证。如果必要的话,每个acquire() 会阻塞当前线程直到许可证可用后获取该许可证。一旦获取到许可证,不需要再释放许可证。

令牌桶算法

RateLimiter使用的是一种叫令牌桶的流控算法,RateLimiter会按照一定的频率往桶里扔令牌,线程拿到令牌才能执行,比如你希望自己的应用程序QPS不要超过1000,那么RateLimiter设置1000的速率后,就会每秒往桶里扔1000个令牌。
在这里插入图片描述

下面我们分别从令牌生成和令牌获取两个流程来解读令牌桶算法︰
令牌生成︰
  1. 这个流程涉及到令牌生成器和令牌桶,令牌桶是一个装令牌的地方,既然是个桶那么必然有一个容量,也就是说令牌桶所能容纳的令牌数星是一个固定的数值。
  2. 对于令牌生成器来说,它会相据一个预定的速率向桶中添加令牌,比如我们可以配置让它以每秒100个请求的速率发放令牌,或者每分钟50个。注意这里的发放速度是匀速,也就是说这50个令牌并非是在每个时间窗口刚开始的时候一次性发放,而是会在这个时间窗口内匀速发放。
  3. 在令牌发放器就是一个水龙头,假如在下面接水的桶子满了,那么自然这个水(令牌)就流到了外面。在令牌发放过程中也一样,令牌桶的容量是有限的,如果当前已经放满了额定容量的令牌,那么新来的令牌就会被丢弃掉。
令牌获取︰
  1. 每个访问请求到来后,必须获取到一个令牌才能执行后面的逻辑。假如令牌的数量少,而访问请求较多的情况下,一部分请求自然无法获取到令牌,那么这个时候我们可以设置一个“缓冲队列"来暂存这些多余的令牌。
  2. 缓冲队列其实是一个可选的选项,并不是所有应用了令牌桶算法的程序都会实现队列。当有缓存队列存在的情况下,那些暂时没有获取到令牌的请求将被放到这个队列中排队,直到新的令牌产生后,再从队列头部拿出一个请求来匹配令牌。
  3. 当队列已满的情况下,这部分访问请求将被丢弃。在实际应用中我们还可以给这个队列加一系列的特效,比如设置队列中请求的存活时间,或者将队列改造为FPriorityqueue,根据某种优先级排序,而不是先进先出。算法是死的,人是活的,先进的生产力来自于不断的创造,在技术领域尤其如此。

方法摘要

在这里插入图片描述

开始撸代码

环境

spring boot 2.1.5
guava 18.0

maven依赖
		<dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>18.0</version>
        </dependency>
Controller
非阻塞限流
	//允许每秒发放2个通行证
    RateLimiter limiter = RateLimiter.create(2.0);

    // 非阻塞限流
    @GetMapping("/tryAcquire")
    public String tryAcquire(Integer count) {

        //询问RateLimiter是否有木有通行证
        if (limiter.tryAcquire(count)) {
            log.info("success, rate is {}", limiter.getRate());
            return "success";
        } else {//没有通行证 出门右转 抛出异常
            log.info("fail, rate is {}", limiter.getRate());
            return "fail";
        }
    }

在这里插入图片描述

在这里插入图片描述

  1. 可以看到同一秒内只有两个通行证 就是会有两个success没通行证就是fail.
  2. 发放令牌是匀速的 可以看到两个success都是基本相隔0.5s所以是每隔0.5s发送一个令牌
限定时间的非阻塞限流
 // 限定时间的非阻塞限流
    @GetMapping("/tryAcquireWithTimeout")
    public String tryAcquireWithTimeout(Integer count, Integer timeout) {
        if (limiter.tryAcquire(count, timeout, TimeUnit.SECONDS)) {
            log.info("success, rate is {}", limiter.getRate());
            return "success";
        } else {
            log.info("fail, rate is {}", limiter.getRate());
            return "fail";
        }
    }

在这里插入图片描述
在这里插入图片描述

  1. 在限定时间内 timeout=2s的时候,2s内不可以发起第二次请求。这样就可以发生获取不到令牌的情况。会给令牌桶足够的时间来生成令牌

注意:在要求的令牌数远大于可以产生的令牌数量时,请求直接失败

同步阻塞限流
    @GetMapping("/acquire")
    public String acquire(Integer count) {
        limiter.acquire(count);
        log.info("success, rate is {}", limiter.getRate());
        return "success";
    }

在这里插入图片描述
在这里插入图片描述

  1. 同步阻塞限流就是在令牌不足的时候会等到令牌桶生产,直到满足到所需要令牌数量然后返回成功。

如有错误
请小伙伴指出交流学习。

https://ifeve.com/guava-ratelimiter/ 参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值