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; }
}
