📄 网关限流功能使用
内部资料,请刷新扫码登录
pigcloud
# 服务限流
原理篇
# 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 的限流
- pigx 动态路由配置 以下参数
- 网关模块配置 bean,#SPEL 表达式去的对应的 bean 多维度限流量的入口
/**
* 自定义限流标志的key,多个维度可以从这里入手
* exchange对象中获取服务ID、请求信息,用户信息等
*/
@Bean
KeyResolver 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<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)));
}