分布式锁需要解决的问题
互斥性 | 任意时刻只能有一个客户端获取到锁 |
---|---|
安全性 | 锁只能由拥有该锁的客户端删除 |
死锁 | 获取锁的客户端因为某些原因宕机而未能释放锁,而导致其他客户端再也无法获取到该锁 |
容错 | 部分节点宕机的时候Redis依然能够获取锁和释放锁 |
如何利用Redis实现分布式锁
在Redis中存在setnx key value
的命令,如果key存在,则创建并赋值
- 时间复杂度:O(1)
- 返回值:设置成功,返回1;设置失败,返回0;
客户端通过去
setnx
(具有原子性)一个key的返回值来判断能否获取到锁
如何解决setnx
长期有效的问题?
为什么需要解决长期有效的问题,线程异常,未正确释放。
expire key seconds
代码实现
long status = redisService.setnx(key,"1");
if(status == 1) {
redisService.expire(key,seconds);
//执行独占资源逻辑
doOccupiedWork();
}
存在的问题
setnx
和expire
两个原子性操作联合起来不在具有原子性,如果在第三行代码执行过程中发生了中断,
那么这个key将一直不会过期。
解决方案
在Redis2.6之后,将setnx
和expire
融合了起来,使其具有原子性,具体操作如下。
SET key value [EX seconds] [PX milliseconds] [NX|XX]
- EX second :设置键的过期时间为second秒
- PX millisecond :设置键的过期时间为millisecond毫秒
- NX :只在键不存在时,才对键进行设置操作
- XX :只在键已经存在时,才对键进行设置操作
- SET操作成功完成时,返回OK ,否则返回nil
代码实现
String result = redisService.set(lockKey,requestId,SET_IF_NOT_EXISTS,SET_WITH_EXPIRE_TIME,expireTime);
if("OK".equals(result)) {
//执行独占资源逻辑
doOccupiedWork();
}
大量的key同时过期的注意事项
存在的问题:集中过期,由于清除大量的key很耗时,会出现短暂的卡顿现象。
解放方案:在设置key的过期时间的时候,给每个key加上随机值
网友评论