背景说明
近期接触到公司一个使用 SpringGate Way 搭建的网关服务,为了保障下游服务,防止用户恶意刷接口造成系统过载崩溃等情况,需要在网关层面引入限流机制。
经过初步调研,不少大佬都推荐使用 Resilience4j 这款轻量级的 Java 容错库来做,但是网上能找到的实践层面的资料比较少,针对特定场景官网的文档也显得捉襟见肘,所以在边学习边实践过程种便有了这篇流水账式的文章。
初体验
1.添加依赖
公司项目使用 Maven 进行依赖管理,在工程的 pom.xml 的 dependencies 节点中添加如下依赖项:
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-cloud2</artifactId>
<version>2.3.0</version>
</dependency>
2.创建限流器工厂类
package com.paratera.aicloud.gateway.filter;
import io.github.resilience4j.ratelimiter.RateLimiter;
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
@Component
public class Resilience4jRateLimiterGatewayFilterFactory extends
AbstractGatewayFilterFactory<Resilience4jRateLimiterGatewayFilterFactory.Config> {
private final RateLimiterRegistry rateLimiterRegistry;
public Resilience4jRateLimiterGatewayFilterFactory(RateLimiterRegistry rateLimiterRegistry) {
super(Config.class);
this.rateLimiterRegistry = rateLimiterRegistry;
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
RateLimiter rateLimiter = rateLimiterRegistry.rateLimiter(config.getName());
return Mono.fromCallable(() -> {
boolean permitted = rateLimiter.acquirePermission();
if (!permitted) {
throw new RuntimeException("Rate limit exceeded");
}
return permitted;
}).then(chain.filter(exchange))
.onErrorResume(RuntimeException.class, e -> {
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete();
});
};
}
public static class Config {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
3.添加限流相关配置
resilience4j:
ratelimiter:
instances:
default:
limitForPeriod: 50 # 每个周期允许的请求数
limitRefreshPeriod: 5s # 限流周期
timeoutDuration: 5s # 等待令牌的超时时间
drainPermissionsOnResult: false # 周期结束后是否清空许可次数
writableStackTraceEnabled: true # 是否生成堆栈跟踪, 可用于减少日志冗余
limit50:
limitForPeriod: 50
limitRefreshPeriod: 300s
timeoutDuration: 500ms
writableStackTraceEnabled: false
4. 路由信息中关联限流配置
在 spring.cloud.gateway.routes 对应的实例节点中添加过滤器,示例如下:
spring:
cloud:
gateway:
routes:
- id: test-RateLimiter
uri: http://localhost:8896
predicates:
- Path=/message/**
filters:
- StripPrefix=1
- name: Resilience4jRateLimiter
args:
name: limit50
本示例核心配置信息如下:
5. 验证
Apifox 自带的自动化测试功能可以很方面的进行并发测试,我们的测试配置如下:
点击 运行 按钮后,得到如下图所示的测试结果,从结果来看式符合限流预期的:
查看请求详情,可以看到请求周期内达到限流场景时,接口是响应的预期内的429状态码:
Links
- Resilience4j 官网文档:https://resilience4j.readme.io/
评论 (0)