SpringCloud之在Zuul上实现微服务粒度的限流(jmeter模拟高并发测试吞吐量实战)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_31122833/article/details/97784250

1、Google Guava提供了限流工具类RateLimiter,在Zuul下添加如下依赖:

        <!--限流-->
        <dependency>
            <groupId>com.marcosbarbero.cloud</groupId>
            <artifactId>spring-cloud-zuul-ratelimit</artifactId>
            <version>1.5.0.RELEASE</version>
        </dependency>

2、在Zuul服务下新加RateLimitZuulFilter类,继承ZuulFilter,源码如下:

@Component
public class RateLimitZuulFilter extends ZuulFilter {

    private Map<String, RateLimiter> map = Maps.newConcurrentMap();

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private SystemPublicMetrics systemPublicMetrics;

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        // 这边的order一定要大于org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter的order
        // 也就是要大于5
        // 否则,RequestContext.getCurrentContext()里拿不到serviceId等数据。
        return 5;
    }

    @Override
    public boolean shouldFilter() {
        // 这里可以考虑弄个限流开启的开关,开启限流返回true,关闭限流返回false,你懂的。
        Collection<Metric<?>> metrics = systemPublicMetrics.metrics();
        Optional<Metric<?>> freeMemoryMetric = metrics.stream()
                .filter(t -> "mem.free".equals(t.getName()))
                .findFirst();
        // 如果不存在这个指标,稳妥起见,返回true,开启限流
        if (!freeMemoryMetric.isPresent()) {
            return true;
        }
        long freeMemory = freeMemoryMetric.get()
                .getValue()
                .longValue();
        // 如果可用内存小于700*1024KB,开启流控
        System.out.println("-----------------------------------freeMemory="+freeMemory);
        return freeMemory < 700*1024L;
    }

    @Override
    public Object run() {
        try {
            RequestContext context = RequestContext.getCurrentContext();
            String key = null;
            // 对于service格式的路由,走RibbonRoutingFilter
            String serviceId = (String) context.get(SERVICE_ID_KEY);
            if (serviceId != null) {
                key = serviceId;
                map.putIfAbsent(serviceId, RateLimiter.create(50));
            }else {
                 // 对于URL格式的路由,走SimpleHostRoutingFilter
                URL routeHost = context.getRouteHost();
                if (routeHost != null) {
                    String url = routeHost.toString();
                    key = url;
                    map.putIfAbsent(url, RateLimiter.create(100));
                }
            }
            RateLimiter rateLimiter = map.get(key);
            if (!rateLimiter.tryAcquire()) {
                accessTokenFail("系统繁忙,请稍后再试!");
            }
        } catch (Exception e) {
            ReflectionUtils.rethrowRuntimeException(e);
        }
        return null;
    }
    /**
     * 请求失败
     * @param message
     */
    public void accessTokenFail(String message){
        Result result = new Result();
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletResponse response = ctx.getResponse();
        ctx.setSendZuulResponse(false);
        result.setType(TypeEnum.FAIL.getCode());
        result.setMessage(message);
        result.setTrue(false);
        result.setCode(TypeEnum.rateLimit.getCode());
        response.setContentType("application/json;charset=UTF-8");
        try {
            response.getWriter().write(objectMapper.writeValueAsString(result));
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

3、为了方便测试,在Zuul配置中添加如下配置:

#目标主机最大连接数和每个主机的初始连接数。
zuul.host.max-total-connections=1000
zuul.host.max-per-route-connections=500
zuul.semaphore.max-semaphores=5000
#设置Hystrix隔离策略为线程池
zuul.ribbon-isolation-strategy=thread
#每个路由使用独立的线程池
zuul.thread-pool.use-separate-thread-pools=true
#修改线程池中的coreSize 默认10
hystrix.threadpool.default.coreSize=500

4、测试内容截图:

1、下载apache的jmeter进行测试
2、在jmeter里新加测试计划:5000个请求在10秒内完成(500/s),这是我在上面配置的线程数
3、启动测试(十秒内当系统freeMemory<700*1024L KB时,开启自动限流,返回‘系统繁忙’)

 

 

 

猜你喜欢

转载自blog.csdn.net/qq_31122833/article/details/97784250