对于很多应用场景来说,除了要求能够限制数据的平均传输速率外,还要求允许某种程度的突发传输。这时候漏桶算法可能就不合适了,令牌桶算法更为适合。令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。
设置 Rate = 2 :每秒放入令牌的个数
桶的大小:100
public class TokenDemo {
//qps:每秒钟处理完请求的次数;tps:每秒钟处理完的事务次数
//代表qps是10;
RateLimiter rateLimiter = RateLimiter.create(10);
public void doSomething(){
if (rateLimiter.tryAcquire()){//rateLimiter.acquire()
//尝试获得令牌.为true则获取令牌成功
System.out.println("正常处理");
}else{
System.out.println("处理失败");
}
}
public static void main(String args[]) throws IOException{
/*
* CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量,此值是线程将要等待的操作数(线程的数量)。
* 当某个线程为了想要执行这些操作而等待时, 它要使用 await()方法。
* 此方法让线程进入休眠直到操作完成。
* 当某个操作结束,它使用countDown() 方法来减少CountDownLatch类的内部计数器,计数器的值就会减1。
* 当计数器到达0时,它表示所有的线程已经完成了任务,这个类会唤醒全部使用await() 方法休眠的线程们恢复执行任务。
*
* */
CountDownLatch latch = new CountDownLatch(1);
Random random = new Random(10);
TokenDemo tokenDemo = new TokenDemo();
for (int i=0;i<20;i++){
new Thread(()->{
try {
latch.await();
Thread.sleep(random.nextInt(1000));
tokenDemo.doSomething();
}catch (InterruptedException e){
e.printStackTrace();
}
}).start();
}
latch.countDown();
System.in.read();
}
}
结果:
正常处理
正常处理
正常处理
正常处理
正常处理
处理失败
正常处理
处理失败
处理失败
处理失败
正常处理
处理失败
正常处理
处理失败
正常处理
正常处理
正常处理
正常处理
处理失败
处理失败
漏桶:漏桶算法能强行限制数据的传输速率。
请求先进入到漏桶里,漏桶以一定的速度出水。当水请求过大会直接溢出,可以看出漏桶算法能强行限制数据的传输速率。进入端无需考虑出水端的速率,就像mq消息队列一样,provider只需要将消息传入队列中,而不需要关心Consumer是否接收到了消息。
对于溢出的水,就是被过滤的数据,可以直接被丢弃,也可以通过某种方式暂时保存,如加入队列之中,像线程池里对溢出数据的4种处理机制一样
网友评论