基于Guava的限流实践
Guava限流是通过令牌木桶的方法来实现,通俗的讲就是有一个木桶,按照每秒固定的平滑的往这个木桶里面放入令牌,当一个请求到来时会首先去这个木桶里面去拿令牌,当获取到令牌才可以继续执行任务,否则就会一直阻塞,或者其他处理办法
实际中用到的几个Guava的RateLimiter几个方法
- RateLimiter create(double permitsPerSecond)
//其中的permitsPerSecond为每秒往令牌里放入几个立牌 - tryAcquire(int permits, long timeout, TimeUnit unit)
//permits为每次获取多少个令牌,默认为1.timeout设置超时时间,如果在超过这个时间没有获得令牌,就会返回false,默认为0 - canAcquire(long nowMicros, long timeoutMicros)
//判断可以拿到令牌返回为boolean类型,nowMicros为当前时间,timeoutMicros为等待时间,其中tryAcquire方法里面就是同步的调用改方法 - acquire(int permits) //获取permits个令牌,返回的是等待时间
实例代码
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
Map<String, RateLimiter> methedToQueue = LimitFlowQueueTool.getQueueTool().getMethedToQueue();//map里面每个接口对应一个限流
String methedName = request.getRequestURI();
/*
判断当前map里面是否存在对应的接口,如果存在调用限流去判断,如果不存在新建一个接口对应限流然后去处理请求
*/
if (methedToQueue != null && methedToQueue.containsKey(methedName)) {
dealLimit(request,response,filterChain,methedName,methedToQueue);
} else {
methedToQueue.put(methedName, RateLimiter.create(1));
dealLimit(request,response,filterChain,methedName,methedToQueue);
}
}
public void dealLimit(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain,String methedName,Map<String, RateLimiter> methedToQueue) throws IOException, ServletException {
RateLimiter rateLimiter = methedToQueue.get(methedName);
if (rateLimiter != null) {
if (rateLimiter.tryAcquire(10, TimeUnit.SECONDS)) {
filterChain.doFilter(request, response);
} else {
ResponseBodyTool.ResponseBody(request, response, new BaseResponse(false,"服务器繁忙"));
}
}
}
该例子使用的是servlet和filter拦截器来实现