RateLimiter原理概述

时间:2024-10-04 09:16:30

 

1. RateLimiter基于令牌桶算法,即以用户设定的恒定速率向令牌桶内放置令牌,用户来执行任务时,只有拿到令牌才能执行;

2. RateLimiter对于持续生成令牌,采用的不是定时任务的方式(过于耗费资源,不适合高并发),而是使用延迟计算的方式,即在获取令牌时计算上一次时间nextFreeTicketMicros和当前时间之间的差值,计算这段时间之内按照用户设定的速率可以生产多少令牌;

  1. void resync(long nowMicros) {
  2. // if nextFreeTicket is in the past, resync to now
  3. if (nowMicros > nextFreeTicketMicros) {
  4. double newPermits = (nowMicros - nextFreeTicketMicros) / coolDownIntervalMicros();//能够生产多少令牌
  5. storedPermits = min(maxPermits, storedPermits + newPermits);
  6. nextFreeTicketMicros = nowMicros;//修改时间
  7. }
  8. }

3. RateLimiter计算延迟时间,即过度消费部分需要由下一次调用买单,因此其具有处理突发流量的能力(就和花呗一样);

  1. final long reserveEarliestAvailable(int requiredPermits, long nowMicros) {
  2. resync(nowMicros);
  3. long returnValue = nextFreeTicketMicros; // 返回的是上次计算的nextFreeTicketMicros
  4. double storedPermitsToSpend = min(requiredPermits, this.storedPermits); // 可以消费的最大令牌数
  5. double freshPermits = requiredPermits - storedPermitsToSpend; // 还需要的令牌数(若需要的大于已有的令牌,则下次请求需要延时等待;否则此值为0,即不需要等待)
  6. long waitMicros =
  7. storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend)
  8. + (long) (freshPermits * stableIntervalMicros); // SmoothBursty为0(SmoothWarmingUp具体计算)+需要等待时间
  9. this.nextFreeTicketMicros = (nextFreeTicketMicros, waitMicros); // 计算此次用了这么多令牌后,下次需要等待到什么时候
  10. this.storedPermits -= storedPermitsToSpend;//减少消耗掉的令牌
  11. return returnValue;
  12. }

4. 对于延迟,RateLimiter使用StopWatch实现不可中断挂起

  1. public boolean tryAcquire(int permits, long timeout, TimeUnit unit) {
  2. long timeoutMicros = ((timeout), 0L);
  3. checkPermits(permits);
  4. long microsToWait;
  5. synchronized(this.mutex()) {
  6. long nowMicros = this.();
  7. if (!this.canAcquire(nowMicros, timeoutMicros)) {
  8. return false;
  9. }
  10. microsToWait = this.reserveAndGetWaitLength(permits, nowMicros);
  11. }
  12. this.(microsToWait);//根据计算出来的时间不可中断挂起
  13. return true;
  14. }

5. RateLimiter由SmoothRateLimiter继承,其中会根据rate计算maxPermits和stableIntervalMicros,并且其有SmoothBursty和SmoothWarmingUp两种方式