例子:短信发送的并发请求问题,是需要限制一个号码一分钟内只能获取一次随机码,一般的接口开发刷新一次接口链接就会发送一次短信,当有大用户量并发时会造成服务器高负载,短信资源的极大浪费,因此有必要做接口的防刷和限流。实现方式可以在前端设定时间,也可以在接口处用缓存做接口限流进行实现。
1.使用Redis incr解决问题
Redis incr 可以实现原子性的递增,可应用于高并发的秒杀活动、分布式序列号生成等场景。这里我使用它来计数实现一分钟内只接受一次请求。
2.设计思路
实现逻辑也很简单:我们在接到短信发送请求后,使用Redis的incr设置一个递增KEY(KEY由固定字符串+手机号码组成),并判断该KEY的数值,如果等于1,说明是第一个请求,我们将该KEY值有效期设置为一分钟;如果该KEY的数值大于1,说明是1分钟内的多次请求,这时我们直接返回短信获取频繁异常。
3.代码实现
3.1 Jedis工具类用到的方法
/**
* 获取缓存自增值
* @param key
* @return
*/
public static long increment(String key) {
long value = 0;
Jedis jedis = null;
try {
jedis = getResource();
value = jedis.incr(key);
logger.debug("get {} = {}", key, value);
} catch (Exception e) {
logger.warn("get {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return value;
}
/**
* 设置某个缓存key的超时时间
* @param key
* @param seconds
*/
public static void expire(String key,int seconds) {
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(key)) {
jedis.expire(key, seconds);
}
} catch (Exception e) {
logger.warn("get {} = {}", key, e);
} finally {
returnResource(jedis);
}
}
3.2 接口限流部分
//接口限流
String redisKey = "SMS_CODE_" + mobile; //缓存键值
long count = JedisUtils.increment(redisKey); //获取发送短信的次数
if(count == 1) {
//设置有效期一分钟
JedisUtils.expire(redisKey, 60);
}else if(count >1) {
rr.setState(ResponseResult.STATE_ERROR);
rr.setMessage("请求太频繁,每分钟只能发送一次短信");
LOG.debug("请求太频繁,每分钟只能发送一次短信");
return rr;
}
//短信发送逻辑
3.3 具体实现类