限流这件事,你可以在网关做也可以在业务服务做,这个取决于自己的需求,我原来的业务是在业务服务做的限流,后来我转移到了网关里面,因为业务服务内做限流会让业务服务处理很多不该处理的请求,这会在一定程度上阻碍其他正常的业务请求,而网关的吞吐量又比较大,所以我最终在网关层做了限流。
除外以上这一点以外,还要考虑一下转移成本,SCG 中的限流是用网关过滤器做的,而网关过滤器又是配合路由使用的,这代表着你只需要使用 SCG 加几下配置就可以针对某个服务做限流(路由),也可以针对所有服务做限流 (默认过滤器),所以如果是转移限流到 SCG 中,那转移成本将会极低,还带来了更大的扩展性。
接下来就开始今天的正文吧~
1. 限流配置
在 SCG 中,处理限流的网关过滤器是:RequestRateLimiter,在源码中它的类名叫做:
RequestRateLimiterGatewayFilterFactory。
由于网关的限流是一个分布式限流,所以必须使用一个中心式的存储来存储限流的状态,在 SCG 使用的就是 Redis,所以你在使用 SCG 的限流器之间首先要引入一个 Redis 依赖,而且由于 SCG 整体是 Reactor 模式的设计,所以你的 Redis 依赖也必须是响应式的:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
引入这个依赖之后,你需要在配置文件中配置上 Redis 的地址:
spring:
redis:
host: 172.31.128.158
database: 0
port: 6379
connect-timeout: 5000
password: root
配置地址完成后你可以启动一下服务查看 Redis 是否能成功连接,没有报错就证明你已经连接成功了。
接下来就该到我们的路由配置环节了,依然使用之前的 user-api 的路由配置为例,我们先配置一个 Path 断言,紧接着给它配置一个过滤器:RequestRateLimiter:
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route((r) -> r.path("/user/**")
.filters(f -> f.requestRateLimiter()
.rateLimiter(RedisRateLimiter.class, c -> c.setReplenishRate(1).setBurstCapacity(10).setRequestedTokens(5))
.configure(c -> c.setKeyResolver(apiTokenKeyResolver()).setDenyEmptyKey(true)))