限流就是限制流量。通过限流,我们可以很好地控制系统的 QPS
,从而达到保护系统的目的。
常见的限流算法有:计数器算法,漏桶(Leaky Bucket
)算法,令牌桶(Token Bucket
)算法。
Spring Cloud Gateway
官方提供了RequestRateLimiterGatewayFilterFactory
过滤器工厂,使用 Redis
和Lua
脚本实现了令牌桶的方式。
在网关服务(
ruoyi-gateway
)的pom.xml
文件中添加spring-boot-starter-data-redis-reactive
依赖
<!-- spring data redis reactive 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
在
application.yml
配置文件中,配置Redis
连接信息,并在spring.cloud.gateway.routes
下配置限流规则
spring:
redis:
host: localhost
port: 6379
password:
cloud:
gateway:
routes:
# 系统模块
- id: ruoyi-system
uri: lb://ruoyi-system
predicates:
- Path=/system/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1 # 令牌桶每秒填充速率
redis-rate-limiter.burstCapacity: 2 # 令牌桶总容量
key-resolver: "#{@pathKeyResolver}" # 使用 SpEL 表达式按名称引用 bean
提示
StripPrefix=1
配置,表示网关转发到业务模块时候会自动截取前缀。
编写
KeyResolverConfiguration
类,实现pathKeyResolver()
方法,返回当前请求的URI
路径作为限流key
package com.ruoyi.gateway.config;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;
/**
* 限流规则配置类
*/
@Configuration
public class KeyResolverConfiguration
{
@Bean
public KeyResolver pathKeyResolver()
{
return exchange -> Mono.just(exchange.getRequest().getURI().getPath());
}
}
启动网关服务RuoYiGatewayApplication.java
和系统服务RuoYiSystemApplication.java
。
因为网关服务有认证鉴权,可以设置一下白名单/system/**
在进行测试,多次请求会发现返回HTTP ERROR 429
,同时在redis
中会操作两个key
,表示限流成功。
request_rate_limiter.{xxx}.timestamp
request_rate_limiter.{xxx}.tokens
其他限流规则
– 参数限流:key-resolver: "#{@parameterKeyResolver}"
@Bean public KeyResolver parameterKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId")); }
- IP限流:
key-resolver: "#{@ipKeyResolver}"
@Bean public KeyResolver ipKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName()); }
powered by kaifamiao