引言:现在AI时代崛起,许多项目都用到外接AI接口做智能问答项目,调用此类接口需要费用,为防止用户恶意刷接口,导致费用超标,可使用基于Redisson的RateLimiter实现分布式限流,控制单用户访问频率。
1.xml引入依赖
<!-- https://github.com/redisson/redisson#quick-start -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.21.3</version>
</dependency>
2. 编写配置类及application.yml配置redis信息
redis:
database: 1
host: localhost
port: 6379
timeout: 5000
@Configuration
@ConfigurationProperties(prefix = "spring.redis")
@Data
public class RedissonConfig {
private Integer database;
private String host;
private Integer port;
private String password;
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer()
.setDatabase(database)
.setAddress("redis://" + host + ":" + port);
RedissonClient redisson = Redisson.create(config);
return redisson;
}
}
3.编写RedisLimiterManager,实现限流操作,示例如下
@Service
public class RedisLimiterManager {
@Resource
private RedissonClient redissonClient;
/**
* 限流操作
*
* @param key 区分不同的限流器,比如不同的用户 id 应该分别统计,确保每个用户或每个资源都有独立的限流器
*/
public void doRateLimit(String key) {
// 创建一个名称为user_limiter的限流器
RRateLimiter rateLimiter = redissonClient.getRateLimiter(key);
//参数代表每秒最多允许请求两次
rateLimiter.trySetRate(RateType.OVERALL, 2, 1, RateIntervalUnit.SECONDS);
// 每当一个操作来了后,请求一个令牌
boolean canOp = rateLimiter.tryAcquire(1);
if (!canOp) {
//如果获取令牌失败(即请求数超过了限制),则抛出异常
throw new BusinessException(ErrorCode.TOO_MANY_REQUEST);
}
}
}
4.在需要该业务的地方使用该方法
// 限流判断,每个用户一个限流器(防止接口被大量请求),这里根据方法+用户id做区分
redisLimiterManager.doRateLimit("genByAi_" + loginUser.getId());