Redis实现限流功能的优点:
- 可以应用于分布式或者集群下
- redis并发量大
Redis限流实现思路
使用redis中key的过期机制、key自增机制,
主类,可以在Filter或者HandlerInterceptor中定义,用于拦截请求
@GetMapping(value = "/limitRate") public ServiceResult limitRate() { ServiceResult serviceResult = null; if(redisManage.getValue("LimitCount")!=null) { Integer countExist = (Integer) redisManage.getValue("LimitCount"); Long expireTimes = redisManage.getExpire("LimitCount"); if(expireTimes>-1) { if(countExist>10) { serviceResult = new ServiceResult(-102,"LimitCount没秒超过10次访问,返回错误"); serviceResult.setData(countExist); return serviceResult; }else { String count = String.valueOf(countExist+1); redisManage.increValue("LimitCount"); serviceResult = new ServiceResult(HttpResultEnum.SUCCESS); serviceResult.setData(count); return serviceResult; } }else { redisManage.delValue("LimitCount"); redisManage.putValueExpireTimes("LimitCount",1,10L); serviceResult = new ServiceResult(100,"LimitCount超时,删除后,创建LimitCount=1"); serviceResult.setData(1); return serviceResult; } }else { redisManage.putValueExpireTimes("LimitCount",1,10L); serviceResult = new ServiceResult(100,"LimitCount不存在,创建LimitCount=1"); serviceResult.setData(1); return serviceResult; } }
Redis实现类
/**
* 自增
* @param key
* @return
*/
public Integer increValue(String key) {
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
try{
valueOperations.increment(key,1);
LoggerUtil.info(logger, "key自增=" + valueOperations.get(key));
}catch (Exception ex) {
ex.printStackTrace();
}
return (Integer) valueOperations.get(key);
}
/**
* 删除Redis中信息
* @param key
* @return
*/
public void delValue(String key) {
LoggerUtil.info(logger, "删除key=" + key);
if (redisTemplate.hasKey(key)) {
redisTemplate.delete(key);
}
}
/**
* 保存信息到Redis中,增加超时时间
* @param key
* @param value
* @param expireTimes default 3600s
*/
public void putValueExpireTimes(String key,String value,Long expireTimes) {
LoggerUtil.info(logger, "保存key=" + key+";value=" + value);
redisTemplate.opsForValue().set(key,value);
if(expireTimes==null || expireTimes == 0L) {
expireTimes = 3600L;
}
redisTemplate.expire(key, expireTimes, TimeUnit.SECONDS);
LoggerUtil.info(logger, "设置超时时间:" + redisTemplate.getExpire(key, TimeUnit.SECONDS));
}
Redis连接池:
import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import redis.clients.jedis.JedisPoolConfig; @Configuration public class RedisConfig { @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; @Value("${spring.redis.timeout}") private int timeout; @Value("${spring.redis.password}") private String password; @Value("${spring.redis.database}") private int database; @Value("${spring.redis.pool.max-idle}") private int maxIdle; @Value("${spring.redis.pool.min-idle}") private int minIdle; @Value("${spring.redis.pool.max-active}") private int maxActive; /** * redis模板,存储关键字是字符串,值是Jdk序列化 * @Description: * @param factory * @return */ @Bean public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) { StringRedisTemplate template = new StringRedisTemplate(factory); setSerializer(template); //设置序列化工具,这样ReportBean不需要实现Serializable接口 template.afterPropertiesSet(); return template; } private void setSerializer(StringRedisTemplate template) { Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); template.setValueSerializer(jackson2JsonRedisSerializer); } /** * redis连接的基础设置 * @Description: * @return */ @Bean public JedisConnectionFactory redisConnectionFactory() { JedisConnectionFactory factory = new JedisConnectionFactory(); factory.setHostName(host); factory.setPort(port); factory.setPassword(password); //存储的库 factory.setDatabase(database); //设置连接超时时间 factory.setTimeout(timeout); factory.setUsePool(true); factory.setPoolConfig(jedisPoolConfig()); return factory; } /** * 连接池配置 * @Description: * @return */ @Bean public JedisPoolConfig jedisPoolConfig() { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxIdle(maxIdle); jedisPoolConfig.setMinIdle(minIdle); jedisPoolConfig.setMaxTotal(maxActive); return jedisPoolConfig; }
}