作者:冷冷zz 来源:https://my.oschina.net/giegie/blog/1838560
# 关于 Spring Cloud Gateway
SpringCloudGateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring云网关旨在提供一种简单而有效的路由API的方法。
Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代Netflix ZUUL,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。
# 开始Gateway 限流
POM 依赖
org.springframework.cloud spring-cloud-starter-gateway org.springframework.boot spring-boot-starter-data-redis-reactive
配置按照请求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、请求信息,用户信息等*/@BeanKeyResolver remoteAddrKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());}
OK 完成。
压力测试
并发5个线程。
Redis 数据变化
我们使用redis的monitor 命令,实时查看redis 的操作情况。
会发现在redis中会操作两个key
request_rate_limiter.{xxx}.timestamp
request_rate_limiter.{xxx}.tokens
# 实现原理
Spring Cloud Gateway 默认实现 Redis限流,如果扩展只需要实现ratelimter接口即可。
# RedisRateLimter 的核心代码,判断是否取到令牌的实现,通过调用 redis的LUA 脚本。
public Mono isAllowed(String routeId, String id) { Config routeConfig = getConfig().getOrDefault(routeId, defaultConfig); int replenishRate = routeConfig.getReplenishRate(); int burstCapacity = routeConfig.getBurstCapacity(); try { List keys = getKeys(id); returns unixtime in seconds. List scriptArgs = Arrays.asList(replenishRate + "", burstCapacity + "", Instant.now().getEpochSecond() + "", "1"); // 这里是核心,执行redis 的LUA 脚本。 FluxLong>> 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 脚本
热门推荐:
- 牛皮!竟然可以用程序修改支付宝(微信)运动步数,横扫榜单~
- 免费版的 IDEA 为啥不能使用 Tomcat ?
- 新媒体管家插件被百度告了,永久停服了~
![6f1c16482b1619b1118c07fe35f9e531.png](https://img-blog.csdnimg.cn/img_convert/6f1c16482b1619b1118c07fe35f9e531.png)
最后,推荐给大家一个有趣有料的公众号:程序员Tools,该公众号主要为大家分享有趣有料的开发者工具,还有老鬼给你带路,永不迷路~
![4e54c0577907201934eb349942e50b62.png](https://img-blog.csdnimg.cn/img_convert/4e54c0577907201934eb349942e50b62.png)
扫描关注,永不迷路
![08f0174df5fb1fce1569801e9b696d05.gif](https://img-blog.csdnimg.cn/img_convert/08f0174df5fb1fce1569801e9b696d05.gif)