分布式锁
redis 实现
setnx 命令
Setnx(SET if Not eXists): 在指定的 key 不存在时,为 key 设置指定的值; 设置成功,返回 1。 设置失败,返回 0;
分布式锁
- 两个服务A,B; 通过Nginx做负载均衡到服务, 两个服务对临界资源进行操作的时候会出现并发问题;
- 所以通过引入Redis做分布式锁;
V1: 通过 Redis 做分布式锁
- 存在的问题
- 假设服务A在阶段4发生了异常, 程序炸了, 那锁就得不到释放, 就锁死了;
- 解决方案
- 增加key的过期时间
V2: 增加key的过期时间
-
存在的问题
-
会把别人的锁释放掉
-
-
解决方案: 使用UUID做服务的唯一标识;
V3: 获取锁时增加唯一UUID,防止释放别人的锁
- 存在的问题
- 删除锁的时候不能保证原子性, 获取lock的value和删除锁不是原子操作, 可能多个线程获取了相同的UUID-B, 然后一顿解锁,,,,,把人家C的锁给删除了, 就完犊子了!
V4: 使用lua, (或者redis事务), 保证删除(释放锁)操作的原子性
- Spring-Data-Redis 支持使用lua脚本
V5: 框架 Redisson
-
redis官方推荐的redis分布式锁方案
-
redisson源码用lua脚本保证原子性
-
集群环境下,依次从各个节点获取锁,半数以上节点获取成功才真正获取锁成功,否则释放已经获取的锁
-
单redis,两个服务访问临界资源的环境下,吞吐量不到700
2点注意
-
redisson 方案性能不好;
-
业务逻辑操作的临界资源都是在redis中存放的前提下, 在lua里写业务逻辑,用Java调,保证原子性,性能很高,单redis,两个服务访问临界资源的环境下, 这种方式吞吐量测试有2000, 比直接用redisson加锁高3倍;