俗话说得好,缓存,限流和降级是系统的三把利剑。刚好项目中每天早上导出数据时因调订单接口频率过高,订单系统担心会对用户侧的使用造成影响,让我们对调用限速一下,所以就正好用上了只
常用的限流算法有两种:<强>漏桶算法强>和<强>令牌桶算法强>。
<强>漏桶算法
强>
漏桶算法:请求先进入“桶”中,然后桶以一定的速率处理请求。如果请求的速率过快会导致桶溢出。根据描述可以知道,漏桶算法会强制限制请求处理的速度。任你请求的再快还是再慢,我都是以这种速率来处理只
但是对于很多情况下,除了要求能够限制平均处理速度外,还要求能允许一定程度的的突发情况。这样的话,漏桶算法就不合适了,用令牌桶算法更合适。
<强>令牌桶算法
强>
令牌桶算法的原理是:系统以恒定的速率往桶里丢一定数量的令牌,请求只有拿到了令牌才能处理。当桶里没有令牌时便可拒绝服务只
番石榴中的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源码分析