Redis(Redisson)分布式锁:多实例锁互斥原理及哈希冲突疑问
问题背景
通用分布式锁场景:为运行多实例的服务实现分布式锁,锁基于1主2从架构的Redis部署。
实现代码
服务实例1
RLock lock11 = redisson.getLock("lock11"); RLock lock12 = redisson.getLock("lock12"); RLock lock13 = redisson.getLock("lock13"); RedissonRedLock lock = new RedissonRedLock(lock11, lock12, lock13); lock.lock(); //... lock.unlock();
服务实例2
RLock lock21 = redisson.getLock("lock21"); RLock lock22 = redisson.getLock("lock22"); RLock lock23 = redisson.getLock("lock23"); RedissonRedLock lock = new RedissonRedLock(lock21, lock22, lock23); lock.lock(); //... lock.unlock();
预期行为
若服务实例1获取锁,则服务实例2无法获取锁(这是分布式锁的正常行为)。
核心疑问
Redis如何识别lock11与lock21需互斥?开发者是否需处理哈希冲突?
解答
嘿,先给你点破一个关键误区:你现在的RedissonRedLock用法完全错了!RedissonRedLock的设计目的是把同一个锁的实例分布在多个Redis节点上,以此来避免单Redis节点故障导致的锁失效,而不是用不同名称的锁来组合成红锁。
你看,实例1用的是lock11、lock12、lock13这三个不同名称的锁,实例2用的是lock21、lock22、lock23,这在Redis眼里就是六组完全独立的锁资源,它们之间根本没有互斥关系,这就是为什么你的预期行为不会生效的原因!
关于Redis如何识别互斥锁
Redis识别互斥锁的核心依据是锁的键名称,而不是你本地Java对象的哈希值——那些对象哈希值只是JVM内部的标识,Redis完全感知不到。要让两个服务实例的锁互斥,你需要让它们针对同一个锁名称,在三个Redis节点上分别获取锁实例,再组合成RedissonRedLock。
举个正确的例子:
实例1和实例2都用"my-distributed-lock"作为锁名称:
// 实例1和实例2都用这段代码创建红锁 RLock lockNode1 = redisson.getLock("my-distributed-lock"); RLock lockNode2 = redisson.getLock("my-distributed-lock"); RLock lockNode3 = redisson.getLock("my-distributed-lock"); RedissonRedLock lock = new RedissonRedLock(lockNode1, lockNode2, lockNode3); lock.lock(); //... lock.unlock();
这样一来,三个Redis节点上存储的锁键都是my-distributed-lock,Redis会把这个键视为唯一的互斥资源,实例1拿到锁后,实例2自然无法获取。
关于哈希冲突的问题
- 首先,你提到的Java对象哈希值和Redis锁的互斥逻辑完全无关,Redis不关心你本地对象的哈希值。
- 其次,Redis本身的键是全局唯一的,只要锁名称相同,就是同一个键;名称不同就是不同键,不存在所谓的“哈希冲突”导致互斥错误的情况。
- 作为开发者,你完全不需要处理任何哈希冲突问题,只要保证需要互斥的服务实例使用完全相同的锁名称来构建红锁就可以了。
总结一下:你当前代码的问题在于用了不同的锁名称,导致两组锁完全独立。修正后使用相同锁名称,Redis就能正确识别互斥关系,达到你想要的分布式锁效果。
内容的提问来源于stack exchange,提问作者Deep

