限流算法有漏桶算法和令牌桶算法,guava的RateLimiter使用的是令牌桶算法也就是以固定的频率向桶中放入令牌,例如一秒钟10枚令牌,实际业务在每次响应请求之前都从桶中获取令牌,只有取到令牌的请求才会被成功响应,获取的方式有两种:阻塞等待令牌或者取不到立即返回失败
image
Guava RateLimiter 使用
/**
* @author haopeng
* @date 2019-07-16 20:17
*/
public class GuavaRateLimiterTest {
@Test
public void testAcquire() {
// acquire(i); 获取令牌,返回阻塞的时间,支持预消费.
RateLimiter limiter = RateLimiter.create(100);
for (int i = 1; i < 20; i++) {
double waitTime = limiter.acquire();
System.out.println("cutTime=" + longToDate(System.currentTimeMillis()) + " acq:" + i + " waitTime:" + waitTime);
}
}
public static String longToDate(long lo){
Date date = new Date(lo);
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sd.format(date);
}
}
每秒1个令牌生成一个令牌,从输出可看出很平滑,这种实现将突发请求速率平均成固定请求速率。
Zuul中使用
@Component
public class RateLimitFilter extends ZuulFilter {
private static final RateLimiter RATE_LIMITER = RateLimiter.create(100);
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public int filterOrder() {
return SERVLET_DETECTION_FILTER_ORDER - 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext requestContext = RequestContext.getCurrentContext();
// 如果获取不到令牌,进行拦截
if (!RATE_LIMITER.tryAcquire()) {
requestContext.setSendZuulResponse(false);
HttpStatus.TOO_MANY_REQUESTS.value()
requestContext.setResponseStatusCode(HttpStatus.BAD_REQUEST.value());
}
return null;
}
}
网友评论