gateway结合redis做限流
本篇是针对已经实现了gateway基础功能的项目,如果需要实现基础功能可以参考 https://www.cnblogs.com/cbzhl/p/17467019.html
针对于并发量比较高的时候,如果不针对对应的服务做限流操作,可能造成服务器压力过大,宕机等情况,为此出现了多种限流的方式:
- 计数器算法(Counter)。 --设计一个计数器,比如一个全局的变量,每次请求后+1,并且在限定时间内比如一分钟,将计数器重置一次。当每次请求时查看计数器是否已经为临界值了,是就限流。但是这个有个缺点就是比如在55秒前没有请求,在55-70秒时有20000次请求,而计数器的临界值则是10000,此时的在60秒时清空了一次,这20000次的请求也是可以进来的。
- 漏桶算法(Leaky Bucket)。--就是所有的请求都放到gateway中,然后再去一个一个分发下去到对应的服务,这样做的缺点就是在大量数据的请求下可能gateway根本无法承受,而下游的服务依然在空闲当中或是毫无压力。
- 令牌桶算法(Token Bucket)。--设计一定数量的令牌,每次请求都会取一个令牌,并且令牌桶会根据规则自动生成令牌。大量请求过来时超过了限定的值,桶里的令牌瞬间被抢空,剩下没有拿到令牌的请求将会失败,并且桶中的令牌一直是有序增加的剩下的请求也能抢到。目前这是一种最优的解决方案。
Gateway的令牌桶算法实现:
Gateway中的限流算法就是采用了令牌桶算法,支持三种令牌桶算法:基于URI限流、基于请求参数限流、基于IP限流。
1.引入依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--redis支持--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency>
2.添加配置信息
server:
port: 9003
eureka:
client:
fetch-registry: true # 从 eureka 服务端获取注册信息
register-with-eureka: true # 将自身注册到 eureka 服务端
service-url:
defaultZone: http://localhost:9000/eureka
instance:
prefer-ip-address: true # 开启采用 IP 注册形式
spring:
application:
name: flowershop-gateway
cloud:
gateway:
routes:
- id: gateway-flower #路由id,唯一
uri: lb://flowershop-common #路由地址,针对哪个服务的路由
predicates: #断言
- Path=/**
filters:
# 指定限流过滤器
- name: RequestRateLimiter
args:
# 基于令牌桶算法,生成令牌的速率
redis-rate-limiter.replenishRate: 1
# 令牌桶的最大容量
redis-rate-limiter.burstCapacity: 1
# 指定生成令牌的算法解析策略,这里是使用了SpEL表达式,获取寻找名字是 keyResolver 的bean对象
key-resolver: "#{@keyResolver}"
redis:
host: 192.168.3.52
database: 0
port: 6379
password:
jedis:
pool:
max-idle: 100
max-wait:
min-idle: 5
timeout: 500
3.令牌算法
Gateway中有多种限流策略,通过URI进行限流、通过请求参数限流、通过IP地址限流,但是我们只可以去实现其中一种。可以去实现 KeyResolver 接口
可以有多种方式实现:在启动类中实现、使用配置类实现
这里我们使用配置类
/** * @Description 令牌桶算法中,令牌的生成算法 * @Author zhl * @Date 2023/6/9 11:22 */ @Configuration public class KeyResolverConfiguration{ @Bean public KeyResolver keyResolver() { return new KeyResolver() { @Override public Mono<String> resolve(ServerWebExchange exchange) { // 这里根据请求【URI】进行限流 return Mono.just(exchange.getRequest().getPath().toString()); } }; } // @Bean // public KeyResolver keyResolver() { // return new KeyResolver() { // @Override // public Mono<String> resolve(ServerWebExchange exchange) { // // 这里根据请求【请求参数username】进行限流 // return Mono.just(exchange.getRequest().getQueryParams().getFirst("username")); // } // }; // } // // @Bean // public KeyResolver keyResolver() { // return new KeyResolver() { // @Override // public Mono<String> resolve(ServerWebExchange exchange) { // // 这里根据请求【IP地址】进行限流 // return Mono.just(exchange.getRequest().getRemoteAddress().getHostName()); // } // }; }
4.运行测试。
利用postman的并发测试
创建一个文件夹
新建请求并保存到这个文件夹中
点击文件夹的三个点(或者是三角符号,因为版本不同)。选择Run collection
查看运行结果,发现很多的429失败,这个就表示被限流了,并且偶尔也会蹦出一些200的成功,进一步证明了上述说的令牌桶中的令牌会自增的机制
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!