美文网首页Spring Cloud
Spring Cloud Gateway 原生支持接口限流该怎么

Spring Cloud Gateway 原生支持接口限流该怎么

作者: 冷冷zz | 来源:发表于2018-07-01 20:13 被阅读451次
    关于pig:

    基于Spring Cloud、oAuth2.0开发基于Vue前后分离的开发平台,支持账号、短信、SSO等多种登录,提供配套视频开发教程。

    码云地址:https://gitee.com/log4j/pig

    关于 Spring Cloud Gateway

    SpringCloudGateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring云网关旨在提供一种简单而有效的路由API的方法。Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代Netflix ZUUL,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。

    zuul如何实现多维度限流请参考我的博客

    Zuul:构建高可用网关之多维度限流

    开始Gateway 限流

    POM 依赖

    <!--spring cloud gateway依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <!--基于 reactive stream 的redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>
    

    配置按照请求IP 的限流

    spring:
      cloud:
        gateway:
          routes:
          - id: requestratelimiter_route
            uri: lb://pigx-upms
            order: 10000
            predicates:
            - Path=/admin/**
            filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1  # 令牌桶的容积
                redis-rate-limiter.burstCapacity: 3  # 流速 每秒
                key-resolver: "#{@remoteAddrKeyResolver}" #SPEL表达式去的对应的bean
            - StripPrefix=1
    

    配置bean,多维度限流量的入口

    /**
    * 自定义限流标志的key,多个维度可以从这里入手
    * exchange对象中获取服务ID、请求信息,用户信息等
    */
    @Bean
    KeyResolver remoteAddrKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }
    

    OK 完成。

    压力测试

    并发5个线程。


    image

    Redis 数据变化

    我们使用redis的monitor 命令,实时查看redis 的操作情况。
    会发现在redis中会操作两个key

    • request_rate_limiter.{xxx}.timestamp
    • request_rate_limiter.{xxx}.tokens


      image

    实现原理

    image

    Spring Cloud Gateway 默认实现 Redis限流,如果扩展只需要实现ratelimter接口即可。

    RedisRateLimter 的核心代码,判断是否取到令牌的实现,通过调用 redis的LUA 脚本。

    public Mono<Response> isAllowed(String routeId, String id) {
        Config routeConfig = getConfig().getOrDefault(routeId, defaultConfig);
        int replenishRate = routeConfig.getReplenishRate();
        int burstCapacity = routeConfig.getBurstCapacity();
    
        try {
            List<String> keys = getKeys(id);
            returns unixtime in seconds.
            List<String> scriptArgs = Arrays.asList(replenishRate + "", burstCapacity + "",
                    Instant.now().getEpochSecond() + "", "1");
            // 这里是核心,执行redis 的LUA 脚本。
            Flux<List<Long>> flux =
            this.redisTemplate.execute(this.script, keys, scriptArgs);
            return flux.onErrorResume(throwable -> Flux.just(Arrays.asList(1L, -1L)))
                    .reduce(new ArrayList<Long>(), (longs, l) -> {
                        longs.addAll(l);
                        return longs;
                    }) .map(results -> {
                        boolean allowed = results.get(0) == 1L;
                        Long tokensLeft = results.get(1);
    
                        Response response = new Response(allowed, getHeaders(routeConfig, tokensLeft));
    
                        if (log.isDebugEnabled()) {
                            log.debug("response: " + response);
                        }
                        return response;
                    });
        }
        catch (Exception e) {
            log.error("Error determining if user allowed from redis", e);
        }
        return Mono.just(new Response(true, getHeaders(routeConfig, -1L)));
    }
    

    LUA 脚本

    image

    相关文章

      网友评论

        本文标题:Spring Cloud Gateway 原生支持接口限流该怎么

        本文链接:https://www.haomeiwen.com/subject/kyshuftx.html