RateLimiter源码分析

  

俗话说得好,缓存,限流和降级是系统的三把利剑。刚好项目中每天早上导出数据时因调订单接口频率过高,订单系统担心会对用户侧的使用造成影响,让我们对调用限速一下,所以就正好用上了只
  

  

常用的限流算法有两种:<强>漏桶算法和<强>令牌桶算法
  

  

<强>漏桶算法
  

  

漏桶算法:请求先进入“桶”中,然后桶以一定的速率处理请求。如果请求的速率过快会导致桶溢出。根据描述可以知道,漏桶算法会强制限制请求处理的速度。任你请求的再快还是再慢,我都是以这种速率来处理只
  

  

但是对于很多情况下,除了要求能够限制平均处理速度外,还要求能允许一定程度的的突发情况。这样的话,漏桶算法就不合适了,用令牌桶算法更合适。
  

  

<强>令牌桶算法
  

  

令牌桶算法的原理是:系统以恒定的速率往桶里丢一定数量的令牌,请求只有拿到了令牌才能处理。当桶里没有令牌时便可拒绝服务只
  

  

番石榴中的Ratelimiter便是实现的令牌桶算法,同时能支持一定程度的突发请求。

        私有静态RateLimiter - - - - - -”);   获得(两个,10);   获得(2,1);   }      

  

输出结果:

        等待时间=0.0   等待时间=0.499163   等待时间=0.489308   -----   等待时间=0.0   等待时间=4.497819      

可以看的到,我们以每秒2个请求的速度生成令牌。对一个来说,当第2次和第3次获取请求的时候,等待的时间加起来就差不多刚好是1秒。对两个来说,当第一次获取了10个令牌之后,第二次获取1个请求,就差不多等待5 s(10/2=5)。可以看的到,番石榴通过限制后面请求的等待时间,来支持一定程度的突发请求。
  

  

<强>接下来,就是通过源码来解析它!,
  

  

当我第一次看到令牌桶的算法描述的时候,我还以为真是有一个线程每隔X秒往一个类似计数器的地方加数字呢…只
  

  

番石榴的限流算法有两种模式,一种是稳定速度,还有一种是生成令牌的速度慢慢提升直到维持在一个稳定的速度。2种模式原理类似,只是在具体等待多久的时间计算上有区别。以下就专门指稳定速度的模式。
  

  

先来看看它的收购()方法:

        公共双收购(int许可){   长microsToWait=储备(凭许可证经营);//先计算获取这些请求需要让线程等待多长时间   stopwatch.sleepMicrosUninterruptibly (microsToWait);//让线程阻塞microTowait微秒长的时间   返回1.0 * microsToWait/SECONDS.toMicros(1升);//返回阻塞的时间   }      

主要分3步:,
  

  

1。根据限幅创建时传入的参数,计算出生成这些数量的令牌需要多长的时间只
  

  

2。让线程阻塞microTowait这么长的时间(单位:微秒),
  

  

3。再返回阻塞了多久,单位:秒
  

  

具体它是怎么计算需要多长时间的呢?让我们来看看储备(许可)方法。

        最后长储备(int许可){   checkPermits(凭许可证经营);//检查参数是否合法   同步(互斥锁()){   返回reserveAndGetWaitLength(许可证,stopwatch.readMicros ());   }   }   ↓   ↓   ↓   最后长reserveAndGetWaitLength (int许可,长nowMicros) {   长momentAvailable=reserveEarliestAvailable(许可证,nowMicros);   返回马克斯(momentAvailable nowMicros, 0);   }   ↓   ↓   ↓   最后长reserveEarliestAvailable (int requiredPermits长nowMicros) {   同步(nowMicros);//长returnValue=https://www.yisu.com/zixun/nextFreeTicketMicros;   双storedPermitsToSpend=min (requiredPermits this.storedPermits);   双freshPermits=requiredPermits - storedPermitsToSpend;   长waitMicros=storedPermitsToWaitTime(这一点。storedPermits storedPermitsToSpend)   +(长)(freshPermits * stableIntervalMicros);   这一点。nextFreeTicketMicros=nextFreeTicketMicros + waitMicros;   这一点。storedPermits -=storedPermitsToSpend;   返回returnValue;   }      

最终调用的是reserveEarliestAvailable方法。先看看同步(nowMicros)方法。

        私人空间同步(长nowMicros) {//如果nextFreeTicket过去,重新同步   如果(nowMicros比;nextFreeTicketMicros) {   storedPermits=min (maxPermits,   storedPermits + (nowMicros - nextFreeTicketMicros)/stableIntervalMicros);   nextFreeTicketMicros=nowMicros;   }   }

RateLimiter源码分析