springboot中使用redis限流
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
application.yml
spring:
redis:
host: 127.0.0.1
port: 6379
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
redis.config
@Configuration
public class RedisConfig {
@Bean
public StringRedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(connectionFactory);
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
/**
* 初始化将lua脚本加载到redis脚本中
* @return 脚本实例
*/
@Bean("limitRedisScript")
public DefaultRedisScript<Boolean> loadRedisScript() {
DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>();
redisScript.setLocation(new ClassPathResource("redisScript/limit.lua"));
redisScript.setResultType(Boolean.class);
return redisScript;
}
}
resource目录下创建redisScript文件夹
limit.lua
local key = KEYS[1] --限流KEY
local limit = tonumber(ARGV[1]) --限流大小
local expireTime = tonumber(ARGV[2]) --过期时间 单位/s
local exists = redis.call("EXISTS", key) --key是否已存在
if exists == 0 then --如果key不存在
redis.call("INCRBY", key, 1) --请求数+1
redis.call("EXPIRE", key, expireTime) --设置1秒过期
else
local current = tonumber(redis.call("get", key) or "0")
if current + 1 > limit then
return false
else
redis.call("INCRBY", key, 1) --请求数+1
end
end
return true
RedisUtil
@Component
public class RedisUtil {
@Resource
private StringRedisTemplate redisTemplate;
@Resource
private RedisScript<Boolean> redisScript;
/**
* 执行lua脚本
* @param keyList rediskey集合
* @param limit 限流大小
* @param expireTime 过期时间 单位/s
* @return
*/
public boolean execute(List<String> keyList, int limit, Long expireTime) {
return redisTemplate.execute(redisScript, keyList, limit, expireTime);
}
}