在分布式系统中,redis应用非常广泛
redis做高并发计数器
业务中常常有要求,譬如一个手机号一分钟限制发送1条短信,我们可以用Redis的Incr自增命令可以轻松实现以上需求
String redisKey = "SMS_PHONE_LIMIT_" + smsPhone;
long count = redisTemplate.opsForValue().increment(redisKey, 1);
if (count == 1) {
//设置有效期一分钟
redisTemplate.expire(redisKey, 60, TimeUnit.SECONDS);
}
if (count > 1) {
resultMap.put("retCode", "-1");
resultMap.put("retMsg", "每分钟只能发送一次短信");
return;
}
还有一个比较重要的场景就是登录错误次数太多,锁定账号5分钟
String redisKey = "USER_LOGIN_LIMIT_";
long count = redisTemplate.opsForValue().increment(redisKey, 1);
//登录错误次数超过5次,则锁定用户3分钟
if (count < 6) {
//成功
//redisTemplate.delete(redisKey);
//失败
redisTemplate.expire(redisKey, 180, TimeUnit.SECONDS);
return ResultUtils.error(-1,"账号密码错误,剩余" + (mustCount-count) + "次机会");
}else {
long time = redisTemplate.getExpire(redisKey);
return ResultUtils.error(-1,"登录失败次数过多,锁定账号"+ time + "秒");
}
分布式锁
上面的计时器也可以做分布式锁,不过在锁定时间很短的时候或者网络延迟的时候,做计时器做分布锁可能会出行死锁
long LOCK_EXPIRE = 1000 * 60;
String lock = "LOCK_PREFIX" + key;
// 利用lambda表达式
Boolean lockFlag = (Boolean) redisTemplate.execute(new RedisCallback() {
@Override
public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
long expireAt = System.currentTimeMillis() + LOCK_EXPIRE + 1;
Boolean acquire = redisConnection.setNX(lock.getBytes(), String.valueOf(expireAt).getBytes());
if (acquire) {
return true;
} else {
byte[] value = redisConnection.get(lock.getBytes());
if (Objects.nonNull(value) && value.length > 0) {
long expireTime = Long.parseLong(new String(value));
if (expireTime < System.currentTimeMillis()) {
// 如果锁已经过期
byte[] oldValue = redisConnection.getSet(lock.getBytes(), String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE + 1).getBytes());
// 防止死锁
return Long.parseLong(new String(oldValue)) < System.currentTimeMillis();
}
}
}
return false;
}
});
return ResultUtils.success(lockFlag);
网友评论