在高并发场景下,往往离不开限流,有基于服务限流、全局限流等,常见的限流算法有漏桶算法和令牌通算法(前一篇文章有讲解)
利用google的Guava框架进行限流,采用的是令牌桶算法,是对java的拓展类库。里面有换一个RateLimiter类
RateLimiterFilter继承ZuulFilter,前置过滤器
package com.chwl.cn.filter;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.HttpStatus;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
/**
* 限流 --在token验证完之后进行
* @author Administrator
*
*/
public class RateLimiterFilter extends ZuulFilter{
private static final Double RATE_LIMITER_NUM=1.0;
private final RateLimiter rateLimiter = RateLimiter.create(RATE_LIMITER_NUM);
@Override
public boolean shouldFilter() {
//如果在此过滤器之前已经有过滤器验证不通过且不需要再执行其他过滤器情况下,判断是否执行此过滤器
RequestContext ctx = RequestContext.getCurrentContext();
if(!ctx.sendZuulResponse()){
return false;
}
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletResponse response = currentContext.getResponse();
response.setContentType("application/json; charset=utf-8");
if(!rateLimiter.tryAcquire()){
currentContext.setSendZuulResponse(false);
response.setStatus(HttpStatus.SC_UNAUTHORIZED);//401
try {
response.getWriter().append("网络繁忙,请稍后再试");
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return -3;
}
}
package com.chwl.cn.filter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Filter {
/**
* token校验处理 order -4
* @return
*/
@Bean
public TokenAuthFilter tokenAuthFilter(){
return new TokenAuthFilter();
}
/**
* 限流处理 order -3
* @return
*/
@Bean
public RateLimiterFilter rateLimiterFilter(){
return new RateLimiterFilter();
}
}
使用起来很简单,但这个限流不太靠谱。
细致到每个微服务的话,简单点就是加一个统一命名的服务判断下就可以了
@Override
public Object run() throws ZuulException {
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletResponse response = currentContext.getResponse();
response.setContentType("application/json; charset=utf-8");
String requestURI = currentContext.getRequest().getRequestURI();
if (requestURI.contains("/apigateway/order")) {//统一的订单服务接口,订单相关的接口都在此应用
if (!rateLimiter.tryAcquire()) {
currentContext.setSendZuulResponse(false);
response.setStatus(HttpStatus.SC_UNAUTHORIZED);// 401
try {
response.getWriter().append("网络繁忙,请稍后再试");
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
server:
port: 7001
#服务的名称
spring:
application:
name: chwl-api-gateway-zuul-7001
# main:
# allow-bean-definition-overriding: true
redis:
# database: 1
host: 127.0.0.1
port: 6379
password:
timeout: 10000
lettuce:
pool:
minIdle: 0
maxIdle: 10
maxWait: 10000
max-active: 10
sentinel:
master: master-6379
nodes: 127.0.0.1:26379,127.0.0.1:26380,127.0.0.1:26381
eureka:
client: #客户端注册进eureka服务列表内
service-url:
#defaultZone: http://localhost:2001/eureka #这个地址就是EurekaServer注册中心的地址
defaultZone: http://ypp:[email protected]:2001/eureka/,http://ypp:[email protected]:2002/eureka/
instance:
instance-id: chwl-api-gateway-zuul-7001
prefer-ip-address: true #访问路径可以显示IP地址
#自定义路由映射
zuul:
routes:
chwl-provider-product: /apigateway/product/**
chwl-provider-order: /apigateway/order/**
chwl-provider-member: /apigateway/member/**
#统一入口为上面的配置,其他入口忽略
ignored-patterns: /*-provider-*/**
#忽略整个服务,对外提供接口
#ignored-services: chwl-provider-product