spring cloud网关通过Zuul RateLimit 限流配置

在平常项目中为了防止一些没有token访问的API被大量无限的调用,需要对一些服务进行API限流。就好比拿一些注册或者发验证码的一些接口,如果被恶意无限的调用,多少会造成一些费用的产生,发短信或者邮件都是一些第三方接口,次数越多,当然费用也就越多了,严重的直接导致服务崩溃。spring cloud api-gateway中引入限流的配置还是必须的。

引入依赖

在pom文件中引入Zuul RateLimit的依赖


<dependency>
    <groupId>com.marcosbarbero.cloud</groupId>
    <artifactId>spring-cloud-zuul-ratelimit</artifactId>
    <version>1.3.2.RELEASE</version>
</dependency>

配置信息


更详细的配置解读下面有写,这里只是简单配置一下,以下这个配置就可以对服务进行限流了
zuul:
  routes: 你的路由配置
    test:
      path: 
      serviceId: 
  ratelimit:
    enabled: true
    policies:
      test: 路由名
        limit: 限制次数
        refresh-interval: 刷新时间
        type: 类型

RateLimit源码简单分析

本地让自己的一个服务配置为一分钟内该服务的API只能访问十次,超过十次,网关就会报错

zuul:
  routes:
    test:
      path: /api/test/**
      serviceId: hscf-cloud-test-9457
  ratelimit:
    enabled: true
    policies:
      test:
        limit: 10
        refresh-interval: 60
        type: origin  限流方式

下面通过源码简要分析一下

RateLimit类是继承ZuulFilter,内中的变量不难看出就是我们在yml文件中配置的属性值。RateLimit内中的部分源码,filterType为“pre”表示在每一个API访问之前进行拦截,LIMIT_HEADER,REMAINING_HEADER,RESET_HEADER这三个变量应该就是获取我们配置的访问次数,还有记录该时间内剩余的访问次数。

public class RateLimitFilter extends ZuulFilter {
    public static final String LIMIT_HEADER = "X-RateLimit-Limit";
    public static final String REMAINING_HEADER = "X-RateLimit-Remaining";
    public static final String RESET_HEADER = "X-RateLimit-Reset";

    public String filterType() {
        return "pre";
    }
    public int filterOrder() {
        return -1;
    }
    public boolean shouldFilter() {
        return this.properties.isEnabled() && this.policy(this.route()).isPresent();
    }

主体逻辑run()中进行判断。先通过this.policy(route).ifPresent((policy)判断policy配置信息是否存在,存在的话会读
取到当前的限制值,还剩余的限制值,最终判断剩余的限制值是否小于0,小于0的话就会报出太多请求的异常
TOO_MANY_REQUESTS(429, "Too Many Requests")

    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletResponse response = ctx.getResponse();
        HttpServletRequest request = ctx.getRequest();
        Route route = this.route();
        this.policy(route).ifPresent((policy) -> {
            String key = this.rateLimitKeyGenerator.key(request, route, policy);
            Rate rate = this.rateLimiter.consume(policy, key);
            response.setHeader("X-RateLimit-Limit", policy.getLimit().toString());
            response.setHeader("X-RateLimit-Remaining", String.valueOf(Math.max(rate.getRemaining().longValue(), 0L)));
            response.setHeader("X-RateLimit-Reset", rate.getReset().toString());
            if(rate.getRemaining().longValue() < 0L) {
                ctx.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
                ctx.put("rateLimitExceeded", "true");
                throw new ZuulRuntimeException(new ZuulException(HttpStatus.TOO_MANY_REQUESTS.toString(), HttpStatus.TOO_MANY_REQUESTS.value(), (String)null));
            }
        });
        return null;
    }
。。。。。。

控制台的异常信息,异常code为429,也就是太多请求的异常:TOO_MANY_REQUESTS(429, "Too Many Requests")

RateLimit详细的配置信息解读

zuul:

    ratelimit:

        key-prefix: your-prefix  #对应用来标识请求的key的前缀

        enabled: true

        repository: REDIS  #对应存储类型(用来存储统计信息)

        behind-proxy: true  #代理之后

        default-policy: #可选 - 针对所有的路由配置的策略,除非特别配置了policies

             limit: 10 #可选 - 每个刷新时间窗口对应的请求数量限制

             quota: 1000 #可选-  每个刷新时间窗口对应的请求时间限制(秒)

              refresh-interval: 60 # 刷新时间窗口的时间,默认值 (秒)

               type: #可选 限流方式

                    - user

                    - origin

                    - url

          policies:

                myServiceId: #特定的路由

                      limit: 10 #可选- 每个刷新时间窗口对应的请求数量限制

                      quota: 1000 #可选-  每个刷新时间窗口对应的请求时间限制(秒)

                      refresh-interval: 60 # 刷新时间窗口的时间,默认值 (秒)

                      type: #可选 限流方式

                          - user

                          - origin

                          - url

  • url类型的限流就是通过请求路径区分
  • origin是通过客户端IP地址区分
  • user是通过登录用户名进行区分,也包括匿名用户

目前只是将网关中的限流方式使用连起来,源码中的原理知道了一下,后续可以继续进行扩展,可以针对请求上的参数进行请求拦截限流

posted @ 2018-09-29 11:08  Levcon  阅读(10543)  评论(0编辑  收藏  举报