guava限流工具RateLimiter
- RateLimiter和java并发工具Semaphore不同的是,RateLimiter约束的是一段时间内的最大访问次数(通常是1秒钟),Semaphore约束的是某一时刻的并发个数,强调的是一个时间点,不是一段时间。
- RateLimter自身是一个抽象类,抽象类SmoothRateLimiter继承RateLimter,最终使用的实现类有两个SmoothBursty和SmoothWarmingUp,SmoothBursty使用的是令牌通算法,SmoothWarmingUp使用的是桶漏算法
- 漏桶算法的原理比较简单,请求进入到漏桶中,漏桶以一定的速率漏水。当请求过多时,水直接溢出。所以SmoothWarmingUp可以保证qps一定小于等于自己的设定值。
- 令牌桶算法的原理是系统以一定速率向桶中放入令牌,如果有请求时,请求会从桶中取出令牌,如果能取到令牌,则可以继续完成请求。SmoothBursty的具体规则是:
- 每秒会有r个令牌放入桶中,或者说,每过1/r秒桶中增加一个令牌,r大于等于0,可以为小数
- 桶中最多存放r个令牌,如果桶满了,新放入的令牌会被丢弃
- 虽然SmoothBursty使用的是令牌桶算法,但不是真的维护一个桶,每隔一段时间放入令牌,而是根据令牌桶的算法建立了数学模型来实现功能
- RateLimiter 有一个有趣的特性是「前人挖坑后人跳」,也就是说 RateLimiter 允许某次请求拿走超出剩余令牌数的令牌,但是下一次请求将为此付出代价,一直等到令牌亏空补上,并且桶中有足够本次请求使用的令牌为止。这里面就涉及到一个权衡,是让前一次请求干等到令牌够用才走掉呢,还是让它先走掉后面的请求等一等呢?Guava 的设计者选择的是后者,先把眼前的活干了,后面的事后面再说。
测试代码
final AtomicInteger count = new AtomicInteger(0);
final RateLimiter limiter = RateLimiter.create(5);
//使用SmoothWarmingUp
//final RateLimiter limiter = RateLimiter.create(5, 100, TimeUnit.MILLISECONDS);
Thread.sleep(2000);//先睡两秒,此时桶里累计的令牌是5个,达到上限
Thread[] threads = new Thread[1000];
for (int i=0;i<1000;i++) {
threads[i]=new Thread(() -> {
limiter.acquire();//acquire()实际调用的是acquire(1),也就是消耗一个令牌
System.out.println(new Date() + "---" + count.incrementAndGet());
});
}
isSecond();//当是整秒时才会放行,否则阻塞,为了从整秒开始观察
for (int i=0;i<1000;i++) {
threads[i].start();
}
for (int i=0;i<1000;i++) {
threads[i].join();
}
//运行结果可以看出,第一秒时因为桶里此时已经有了满了有5个令牌,所以被访问了10次,再然后就稳定在5qps,如果使用SmoothWarmingUp,则不会这样
Sat Mar 31 23:38:20 CST 2018---1
Sat Mar 31 23:38:20 CST 2018---2
Sat Mar 31 23:38:20 CST 2018---3
Sat Mar 31 23:38:20 CST 2018---4
Sat Mar 31 23:38:20 CST 2018---6
Sat Mar 31 23:38:20 CST 2018---5
Sat Mar 31 23:38:20 CST 2018---7
Sat Mar 31 23:38:20 CST 2018---8
Sat Mar 31 23:38:20 CST 2018---9
Sat Mar 31 23:38:20 CST 2018---10
Sat Mar 31 23:38:21 CST 2018---11
Sat Mar 31 23:38:21 CST 2018---12
Sat Mar 31 23:38:21 CST 2018---13
Sat Mar 31 23:38:21 CST 2018---14
Sat Mar 31 23:38:21 CST 2018---15
Sat Mar 31 23:38:22 CST 2018---16
Sat Mar 31 23:38:22 CST 2018---17
Sat Mar 31 23:38:22 CST 2018---18
Sat Mar 31 23:38:22 CST 2018---19
Sat Mar 31 23:38:22 CST 2018---20
所以SmoothBursty可以保证大流量时(令牌的需求量大于产生量),qps可以保持在稳定值。反之由于令牌可以保存,qps会高于稳定值。SmoothWarmingUp则会保证qps永远都不超过设定值
网友评论