限流算法有漏桶算法和令牌桶算法,guava的RateLimiter使用的是令牌桶算法也就是以固定的頻率向桶中放入令牌箫章,例如一秒鐘10枚令牌晤硕,實(shí)際業(yè)務(wù)在每次響應(yīng)請求之前都從桶中獲取令牌,只有取到令牌的請求才會被成功響應(yīng)裹虫,獲取的方式有兩種:阻塞等待令牌或者取不到立即返回失敗
image
Guava RateLimiter 使用
/**
* @author haopeng
* @date 2019-07-16 20:17
*/
public class GuavaRateLimiterTest {
@Test
public void testAcquire() {
// acquire(i); 獲取令牌有滑,返回阻塞的時(shí)間,支持預(yù)消費(fè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個(gè)令牌生成一個(gè)令牌晋南,從輸出可看出很平滑藏古,這種實(shí)現(xiàn)將突發(fā)請求速率平均成固定請求速率增炭。
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();
// 如果獲取不到令牌,進(jìn)行攔截
if (!RATE_LIMITER.tryAcquire()) {
requestContext.setSendZuulResponse(false);
HttpStatus.TOO_MANY_REQUESTS.value()
requestContext.setResponseStatusCode(HttpStatus.BAD_REQUEST.value());
}
return null;
}
}