Spring Cloud Gateway 原生的接口限流该怎么玩

作者:冷冷gg

来源:https://my.oschina.net/giegie/blog/1838560


你想学习Java ?资源都在这里了「点击查看」


关于 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 依赖


 
 
  1. <!--spring cloud gateway依赖-->

  2. <dependency>

  3.    <groupId>org.springframework.cloud</groupId>

  4.    <artifactId>spring-cloud-starter-gateway</artifactId>

  5. </dependency>

  6. <!--基于 reactive stream 的redis -->

  7. <dependency>

  8.    <groupId>org.springframework.boot</groupId>

  9.    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>

  10. </dependency>


配置按照请求IP 的限流


 
 
  1. spring:

  2.  cloud:

  3.    gateway:

  4.      routes:

  5.      - id: requestratelimiter_route

  6.        uri: lb://pigx-upms

  7.        order: 10000

  8.        predicates:

  9.        - Path=/admin/**

  10.        filters:

  11.        - name: RequestRateLimiter

  12.          args:

  13.            redis-rate-limiter.replenishRate: 1  # 令牌桶的容积

  14.            redis-rate-limiter.burstCapacity: 3  # 流速 每秒

  15.            key-resolver: "#{@remoteAddrKeyResolver}" #SPEL表达式去的对应的bean

  16.        - StripPrefix=1


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


 
 
  1. /**

  2. * 自定义限流标志的key,多个维度可以从这里入手

  3. * exchange对象中获取服务ID、请求信息,用户信息等

  4. */

  5. @Bean

  6. KeyResolver remoteAddrKeyResolver() {

  7.    return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());

  8. }


OK 完成。


压力测试 


并发5个线程。 

640?wx_fmt=png


Redis 数据变化 


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

  • requestratelimiter.{xxx}.timestamp 

  • requestratelimiter.{xxx}.tokens  

640?wx_fmt=png


实现原理


640?wx_fmt=png


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


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


 
 
  1. public Mono<Response> isAllowed(String routeId, String id) {

  2.    Config routeConfig = getConfig().getOrDefault(routeId, defaultConfig);

  3.    int replenishRate = routeConfig.getReplenishRate();

  4.    int burstCapacity = routeConfig.getBurstCapacity();

  5.    try {

  6.        List<String> keys = getKeys(id);

  7.        returns unixtime in seconds.

  8.        List<String> scriptArgs = Arrays.asList(replenishRate + "", burstCapacity + "",

  9.                Instant.now().getEpochSecond() + "", "1");

  10.        // 这里是核心,执行redis 的LUA 脚本。

  11.        Flux<List<Long>> flux =

  12.        this.redisTemplate.execute(this.script, keys, scriptArgs);

  13.        return flux.onErrorResume(throwable -> Flux.just(Arrays.asList(1L, -1L)))

  14.                .reduce(new ArrayList<Long>(), (longs, l) -> {

  15.                    longs.addAll(l);

  16.                    return longs;

  17.                }) .map(results -> {

  18.                    boolean allowed = results.get(0) == 1L;

  19.                    Long tokensLeft = results.get(1);

  20.                    Response response = new Response(allowed, getHeaders(routeConfig, tokensLeft));

  21.                    if (log.isDebugEnabled()) {

  22.                        log.debug("response: " + response);

  23.                    }

  24.                    return response;

  25.                });

  26.    }

  27.    catch (Exception e) {

  28.        log.error("Error determining if user allowed from redis", e);

  29.    }

  30.    return Mono.just(new Response(true, getHeaders(routeConfig, -1L)));

  31. }


LUA 脚本


640?wx_fmt=png


-END-


 近期热文:

关注我

640?wx_fmt=jpeg

点击“阅读原文”,看本号其他精彩内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值