利用RequestRateLimiter实现简单限流
自己做的微服务网站今天终于算是上线了(内部测试),虽然是内部测试,但在上线之前还是考虑做了一下gateway网关的限流,担心群众里面有坏人🐍
利用RequestRateLimiter实现简单限流
RequestRateLimiter是gateway自带的 过滤器。
RequestRateLimiter 过滤器可以基于令牌桶算法实现请求限流。其具体原理如下:
创建令牌桶:在 RequestRateLimiter 过滤器初始化时,会读取配置参数创建对应的令牌桶。
生成令牌:当新的请求到达 RequestRateLimiter 过滤器时,它会检查令牌桶中是否有足够的令牌。如果有,则从令牌桶中移除一个令牌;否则请求被拒绝。
限制连接数:在超出最大连接数之后会在队列里等待。
计时更新令牌桶大小:RequestRateLimiter 过滤器会定期计时更新令牌桶的大小,确保让进入的请求有机会得到执行,同时防止恶意攻击或者系统故障导致服务器负载过重。
在使用 RequestRateLimiter 过滤器时,我们可以通过设置参数 replenishRate
和 burstCapacity
来控制令牌桶的填充速率和容量,然后将其与特定的路由或服务进行绑定,以实现对特定接口的限流效果。
资料来源——知乎用户:苏格拉没有底
实现流程
引入redis依赖并配置连接信息
RequestRateLimiter 一般会依赖 ReactiveStringRedisTemplate, 而它又依赖到 ReactiveRedisConnectionFactory 的实现类LettuceConnectionFactory1
2
3<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
<version>2.2.5.RELEASE</version>实现限流策略
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30/**
* @Author 林峰
* @Date 2024/4/6 10:22
* @Version 1.0
*/
public class RequestRateLimiterResolver {
public KeyResolver ipKeyResolver(){
// ip限流
return exchange -> Mono.just(
exchange.getRequest()
.getHeaders()
.getFirst("X-Forwarded-For")
);
}
public KeyResolver pathKeyResolver(){
// 根据请求路径限流
return exchange -> Mono.just(
exchange.getRequest()
.getPath()
.toString()
);
}
}过滤器接受一个可选的keyResolver参数和特定于速率限制器的参数。该参数的作用就是用来根据你设定的规则生成key,比如在redis中使用什么key。
配置限流
1
2
3
4
5
6
7
8
9
10
11
12
13
14- id: subject # 路由ID 刷题模块
uri: lb://al-club-subject
predicates:
- Path=/subject/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
# 令牌桶填充速率
redis-rate-limiter.replenishRate: 50
# 令牌桶上限
redis-rate-limiter.burstCapacity: 50
# 获取Bean对象
key-resolver: "#{@pathKeyResolver}"“#{@pathKeyResolver}”是一个SpEL表达式,它引用了一个名为userKeyResolver的bean,也就是我们刚刚定义的KeyResolver,这样就可以实现一个简单的限流。
测试结果
修改nacos上的配置,改小一点,方便演示
进行一次小小的压测(软件是apifox)
结果
可以看到限流成功,失败请求的错误码为429,代表Too many Requests