限流-令牌桶

1. 背景

1.1 为什么需要限流

  • 大量正常用户高频访问导致服务器宕机
  • 恶意用户高频访问导致服务器宕机
  • 网页爬虫 ,对于这些情况我们需要对用户的访问进行限流访问

1.2 介绍

       目前主流的限流算法:令牌、漏桶、滑动窗口。Nginx都实现了漏桶算法,Springcloud Gateway和Guava Ratelimiter实现了令牌桶,阿里的 Sentinel实现了滑动窗口。

       如图所示,令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务,令牌桶算法通过发放令牌,根据令牌的rate频率做请求频率限制,容量限制等。

2. 源码 

2.1 Guava RateLimiter如何实现令牌桶

       令牌桶传统的思路是攒够了N个令牌后,再分配。但是Guava是先分配,然后将下次分配的时间移后。

       举例说明:假设每秒可分配10个令牌,当前时间为2s,所以已存储了20个令牌,现在我要分配30个令牌,一种做法是等待1秒,在第3秒的时候攒够30个了,然后分配返回分配令牌;而Guava的做法是,直接返回,然后将下一个分配令牌的时间点定为第3秒。这两种情况都实现了3秒钟分配30个令牌的QPS需求。

2.1.1 如何申请令牌

public boolean tryAcquire(int permits, long timeout, TimeUnit unit) {
    long timeoutMicros = max(unit.toMicros(timeout), 0);
    checkPermits(permits);
    long microsToWait;
    synchronized (mutex()) {
      // 秒表,也就是类似跑步用的秒表计数器,用来统计自开始掐秒表后过去了多少时间,可以重置秒表归0
      long nowMicros = stopwatch.readMicros();
      // 判断是否可以在timeoutMicros时间范围内获取令牌,公式:下次令牌可领取时间(相对时间)-超时时间>秒表时间
      if (!canAcquire(nowMicros, timeoutMicros)) {
        return false;
      } else {
         // 获取令牌,并返回需要等待的毫秒数
        microsToWait = reserveAndGetWaitLength(permits, nowMicros);
      }
    }
    // 先获取令牌,再等待
    stopwatch.sleepMicrosUninterruptibly(microsToWait);
    return true;
}

2.1.2 谁发令牌

    申请的时候会每次重新同步,将秒表的时间与下次可领取令牌的时间进行对比

void resync(long nowMicros) {
    // if nextFreeTicket is in the past, resync to now
    if (nowMicros > nextFreeTicketMicros) {
      // 计算该时间差里令牌的产生数量,coolDownIntervalMicros为每个令牌产生需要的时间
      double newPermits = (nowMicros - nextFreeTicketMicros) / coolDownIntervalMicros();
      // 这里是为了防止超出最大限制
      storedPermits = min(maxPermits, storedPermits + newPermits);
      nextFreeTicketMicros = nowMicros;
    }
}

3. 实战

4. FAQ

4.1 Guava令牌的发放形式将下次分配的时间移后,那会不会无限超前消费?

4.2 从源码看,Guava 先获取令牌再进行等待,这跟先等待,再获取令牌有什么区别?

4.3 guava限流用的synchronized,这样性能是不是值得考究?

5. 参考资料

Guava之Stopwatch

Guava令牌桶RateLimiter原理和源码解析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值