Spring Cloud Gateway 内置了一个限流功能的过滤器工厂,那就是RequestRateLimiterGatewayFilterFactory ,它使用 Redis 和 Lua 脚本实现令牌桶算法的方式进行限流,允许你根据不同的规则(如 IP、URL、参数等)来限制请求的频率,可以根据访问速率和令牌桶容量来限制路由的访问。
令牌桶算法是一种常用的流量控制算法,常用于限制对某个资源或服务的并发访问数或请求速率。该算法基于一个固定容量的令牌桶,每个请求需要消耗一个令牌才能被处理,当令牌桶为空时,则拒绝请求或将请求放入等待队列中。同时,令牌桶会以一定的速率生成令牌。
令牌桶算法的实现通常涉及两个参数:令牌生成速率和令牌桶容量。令牌生成速率指的是每秒钟向令牌桶中添加的令牌数量,令牌桶容量指的是令牌桶最多能存储的令牌数量。
例如,如果令牌生成速率为10,令牌桶容量为20,如果令牌桶为空时,则每秒钟最多可以处理10个请求,当令牌桶满的时候,则每秒可以额外处理多20个请求。
令牌桶算法优点
平滑限流:令牌桶算法可以平滑地限制流量,避免突发限流的情况。它能够在一段时间内平均处理请求流量,而不是对每个请求进行严格限制。
适应突发流量:令牌桶算法能够适应突发流量的情况,例如在互联网应用中常见的用户突然涌入的情况。由于令牌桶可以存储一定数量的令牌,因此可以应对短时间内的流量激增,而不会导致流量瓶颈或系统过载。
可配置性:令牌桶算法的参数(如令牌生成速率、令牌桶容量等)可以根据实际需求进行调整,以满足不同的限流需求。这种可配置性使得令牌桶算法具有很大的灵活性。
1、配置Redis:
因为RequestRateLimiterGatewayFilterFactory 过滤器工厂是使用redis来进行限流的,所以需要在Spring Boot的配置文件中,配置Redis连接信息。例如:
spring:
redis:
host: localhost
port: 6379
2、配置限流过滤器: 在Spring Cloud Gateway的配置文件中,为需要进行限流的路由配置限流过滤器。例如:
spring:
cloud:
gateway:
routes:
- id: my_route
uri: http://example.com
predicates:
- Path=/my_route/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenish-rate: 10
redis-rate-limiter.burst-capacity: 20
key-resolver: "#{@remoteAddrKeyResolver}"
上述配置中,my_route是需要进行限流的路由配置,RequestRateLimiter是使用RequestRateLimiterGatewayFilterFactory实现限流的过滤器。redis-rate-limiter.replenish-rate参数指定了每秒钟生成的令牌数,redis-rate-limiter.burst-capacity参数指定了令牌桶的容量。
key-resolver:用于获取限流维度的实现类,可以根据ip、uri、设备号、用户id等进行限流,这里的remoteAddrKeyResolver是一个自定义的KeyResolver实现类,用于根据请求的远程地址来生成限流的Key。
3、实现KeyResolver: 创建自定义的KeyResolver实现类
限流的过滤器需要根据一定的规则来确定流量的标识,通过实现KeyResolver接口可以定义我们的流量维度
下面就是根据请求的远程地址来生成限流的Key
@Component("remoteAddrKeyResolver")
public class RemoteAddrKeyResolver implements KeyResolver {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
}
注:bean名需要与我们配置文件使用的key-resolver名称一致
以上步骤完成后,RequestRateLimiterGatewayFilterFactory就会自动根据规则生成限流的Key,并根据配置的令牌桶容量和每秒钟生成的令牌数来限制路由访问速率。