RateLimiter - YUHAO-ZX/StudyCollection GitHub Wiki

google RateLimiter 解读

1.使用

RateLimiter r = RateLimiter.create(10);
        for(int i=0;i<10;i++){
            if(!r.tryAcquire()){
                //TODO 被限流
                return ;
            }
            //TODO 业务代码
        }

2.源码:tryAcquire()

public boolean tryAcquire(int permits, long timeout, TimeUnit unit) {
    long timeoutMicros = max(unit.toMicros(timeout), 0);//获取超时
    checkPermits(permits);//参数检测
    long microsToWait;
    synchronized (mutex()) {//锁
      long nowMicros = stopwatch.readMicros();//读取stopwatch创建后到此刻的微秒数(1微秒=1/1000 毫秒)
      if (!canAcquire(nowMicros, timeoutMicros)) {//判断是否被限流
        return false;
      } else {
        microsToWait = reserveAndGetWaitLength(permits, nowMicros);//核心函数,处理限流逻辑
      }
    }
    stopwatch.sleepMicrosUninterruptibly(microsToWait);
    return true;
  }

3.reserveAndGetWaitLengt()

private long reserveNextTicket(double requiredPermits, long nowMicros) {
    resync(nowMicros);//!!更新令牌,限流时间
    long microsToNextFreeTicket = nextFreeTicketMicros - nowMicros;
    //计算此次调用能够获取的令牌数
    double storedPermitsToSpend = Math.min(requiredPermits, this.storedPermits);
    //计算还没有获取到的令牌数
    double freshPermits = requiredPermits - storedPermitsToSpend;

    //!!storedPermitsToWaitTime 返回0 , stableIntervalMicros  为  (1/限流数)*1000000
    long waitMicros = storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend)
        + (long) (freshPermits * stableIntervalMicros);
    //!!计算时间,在此时间之前不能再接收新的请求,请求将被被拒绝
    this.nextFreeTicketMicros = nextFreeTicketMicros + waitMicros;
    this.storedPermits -= storedPermitsToSpend;
    return microsToNextFreeTicket;
  }

4.resync()

private void resync(long nowMicros) {
    // if nextFreeTicket is in the past, resync to now
    //storedPermits 代表可用令牌数目,stableIntervalMicros  为  (1/限流数)*1000000
    if (nowMicros > nextFreeTicketMicros) {
      storedPermits = Math.min(maxPermits,
          //计算可用令牌数:可用令牌+(两次请求间隔(秒)* 限流数)(相当于这段时间内均摊的可获取令牌数)
          storedPermits + (nowMicros - nextFreeTicketMicros) / stableIntervalMicros);
      nextFreeTicketMicros = nowMicros;//更新nextFreeTicketMicros 为当前时间
    }
  }

5.解读

从上面分析可以得出,底层会每隔:1/限流数(s) 放入一个令牌(并不是真正意义上的每秒限流多少次),然后外部请求去消费,可能存在高并发情况下先到的请求被挡掉。