为啥要接口限流?
为了防止QPS过高而导致服务宕机。
1、QPS是什么?
接口流量峰值,同一时间访问的最大人数 (读写) 一般大概约为1000+ 也就是1000QPS。单读的话可以达到3000+。当然写的强度和你的业务复杂度有关,一般业务不复杂,1000+没啥问题,机器是可以顶的住的。
2、结合cloud zuul网关设计限流方案
首先来了解下 zuul 网关的生命周期
每个阶段出现错误的执行情况
当 pre 出现异常 ——>error ——>post——>HTTP
当 routing 出现异常——>error——>post——>HTTP
当 error 出现异常——>post——>HTTP
当 post 出现异常——>error——>HTTP
zuulfilter的使用
/**
* @author wyy
* @date 19/5/23
* zuul filter过滤器
*/
@Component
public class LoginFilter extends ZuulFilter {
/**
* filter类型 前置filter 和后置filter
* 是以constant定义的
* @return
*/
@Override
public String filterType() {
return PRE_TYPE;
}
/**
* 过滤器顺序 越小越先执行
* @return
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 过滤器是否生效 true 生效 false 不生效
* @return
*/
@Override
public boolean shouldFilter() {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
System.out.println(request.getRequestURI());
//ACL 拦截下面的接口 忽略大小写 拼写接口需要和网关自定义接口一致
if ("/apigateway/order/api/v1/order/save".equalsIgnoreCase(request.getRequestURI())){
return true;
}else if ("/apigateway/order/api/v1/order/list".equalsIgnoreCase(request.getRequestURI())){
return true;
}else if ("/apigateway/order/api/v1/order/find".equalsIgnoreCase(request.getRequestURI())){
return true;
}
return false;
}
/**
* 业务处理逻辑 和thread run()方法有点像
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
//如果上面的拦截生效 并true 就会跳到这里进行业务逻辑处理
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
String token = request.getHeader("token");
if(StringUtils.isBlank(token)){
token = request .getParameter("token");
}
//登录校验逻辑 根据公司情况自定义 JWT
if(StringUtils.isBlank(token)){
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
}
return null;
}
}
接口限流 guava框架 限流原理
实现代码
/**
* 使用guava限流框架
* @author wyy
* @date
*/
public class OrderRateLimitFilter extends ZuulFilter {
//每一秒生成1000个令牌 根据接口的压力来规定有多少个令牌
private static final RateLimiter RATE_LIMITER = RateLimiter.create(1000);
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public int filterOrder() {
return -4;
}
@Override
public boolean shouldFilter() {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
/* System.out.println(request.getRequestURI());*/
//需要对那个接口限流就把哪个接口写下去
//ACL 拦截下面的接口 忽略大小写
if ("/apigateway/order/api/v1/order/save".equalsIgnoreCase(request.getRequestURI())) {
return true;
}
return false;
}
@Override
public Object run() throws ZuulException {
RequestContext requestContext = RequestContext.getCurrentContext();
if (!RATE_LIMITER.tryAcquire()) {
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
}
return null;
}
}