我们系统现在架构是收到mq消息,先放到redis队列,然后再从redis队列取任务去消费,当上游刷数据的时候,redis队列任务就会非常多,这个时候我们在消费的时候既要考虑redis的稳定性,也要考虑调用下游资源所能提供资源能力。对于资源受限、处理能力不是很强的资源应当给予保护(在下游资源无法或者短时间内无法提升处理性能的情况下)。可以使用限流器或者类似保护机制,避免下游服务崩溃造成整体服务的不可用。这是我们用到了Guava的令牌桶算法RateLimiter
RateLimiter类似于JDK的信号量Semphore,他用来限制对资源并发访问的线程数
RateLimiter limiter = RateLimiter.create(10); //每秒不超过10个任务被提交
limiter.acquire(); //请求RateLimiter, 超过10个会被阻塞
executor.submit(runnable); //提交任务
也可以以非阻塞的形式来使用:
If(limiter.tryAcquire()){ //未请求到limiter则立即返回false
doSomething();
}else{
doSomethingElse();
}
下面可以看代码测试,通过例子就能理解出原理
public static void main(String args[]){
//5000当前程序耗时:2007ms
//40000当前程序耗时:259ms
//不加速率当前程序耗时:2ms 如果不限速相当于2毫秒就能处理完,
long startTime=System.currentTimeMillis();
/**
* 每秒的令牌数是10000
* 限速后根据大小,设置的令牌越小,处理速度越慢,设置的令牌数越大,速度越快
*/
RateLimiter rateLimiter = RateLimiter.create(40000);
//rateLimiter.setRate(40000);
//下面是一些测试代码
for(int i=0;i<10000;i++){
rateLimiter.acquire();
}
long endTime=System.currentTimeMillis();
System.out.println("当前程序耗时:"+(endTime-startTime)+"ms");
}
下面是介绍RateLimiter的博客
http://ifeve.com/guava-ratelimiter/
http://blog.csdn.net/cloud_ll/article/details/43602325
http://www.voidcn.com/blog/jiesa/article/p-4943128.html
http://www.jianshu.com/p/3dfae5c15eb9