实战篇 21. 分布式锁 - Redisson 主从一致性与 MultiLock 联锁

6 阅读3分钟

📚 实战篇 21. 分布式锁 - Redisson 主从一致性与 MultiLock 联锁

一、 核心痛点:主从集群下的“锁丢失”问题(脑裂)

在真实的生产环境中,为了保证 Redis 的高可用,我们通常不会只部署一台单机 Redis,而是会搭建主从集群(Master-Slave)

  • 正常的读写分离: Java 客户端在加锁时,只会向 Master(主节点)写入数据。Master 写入成功后,会异步将这把锁的数据同步给 Slave(从节点)。

💥 灾难场景(极端并发缺陷):

  1. 线程 1 加锁成功: 线程 1 向 Master 节点发送加锁请求,Master 记录了这把锁。
  2. 异步同步未完成,Master 宕机: 就在 Master 准备把锁信息同步给 Slave 的零点几毫秒内,Master 服务器突然断电宕机了!此时,Slave 节点里根本没有这把锁的数据
  3. 主从切换(哨兵机制): 监控系统发现 Master 挂了,迅速把 Slave 提拔为新的 Master。
  4. 线程 2 趁虚而入: 此时线程 2 过来请求加锁,它访问的是新的 Master。新 Master 一查,发现自己身上没有锁,于是允许线程 2 加锁成功。
  5. 后果: 线程 1 和线程 2 同时拿到了同一把锁!高并发防线再次全面崩溃。

二、 终极破局:MultiLock(联锁)的设计思想

为了彻底根除主从同步带来的时间差漏洞,Redis 的作者提出了 RedLock(红锁) 算法,而 Redisson 完美实现了它,并提供了更为通用的 MultiLock(联锁)

结合你上传的架构图,MultiLock 的核心思想是:抛弃主从复制,改用多个独立的 Redis 节点。

  1. 部署架构的改变: 不再区分谁是主、谁是从。直接搭建 3 个(或 5 个、7 个,通常为奇数)完全相互独立的 Redis 节点(如 Node 1, Node 2, Node 3)。它们之间不进行任何数据同步

  2. 加锁逻辑的改变:

    • 当 Java 客户端(线程 1)想要加锁时,它必须按顺序依次向这 3 个独立的节点发送加锁请求。
    • 只有当它在这 3 个节点上都加锁成功(或者满足绝大多数节点成功,比如 3 个中成功了 2 个),这把分布式锁才算真正获取成功!

三、 为什么 MultiLock 能解决宕机丢失问题?

假设我们采用了图中的 3 节点 MultiLock 架构:

  1. 正常情况: 线程 1 在 Node 1、Node 2、Node 3 上都成功写入了锁标识。

  2. 某个节点宕机: 突然,Node 1 宕机了。

  3. 线程 2 尝试加锁: 线程 2 跑过来,它也会依次向剩下的节点请求加锁。

    • 结果它发现在 Node 2 和 Node 3 上,锁已经被线程 1 占用了
    • 因为线程 2 无法在大多数节点上拿到锁,所以它加锁失败!
  4. 结论: 只要不是所有的独立节点在同一瞬间全部宕机(概率极低),锁的状态就是绝对安全的。


四、 核心代码落地(了解即可)

在代码层面,使用 Redisson 的 MultiLock 非常简单,你只需要分别获取各个节点的锁对象,然后将它们组合起来即可:

Java

// 1. 获取多个独立的锁对象 (假设配置了三个不同客户端指向不同的 Redis 实例)
RLock lock1 = redissonClient1.getLock("order");
RLock lock2 = redissonClient2.getLock("order");
RLock lock3 = redissonClient3.getLock("order");

// 2. 将它们组合成一个 MultiLock
RLock multiLock = redissonClient1.getMultiLock(lock1, lock2, lock3);

// 3. 尝试获取联锁
// 这里的逻辑是:必须所有节点都获取成功,才算真正成功
boolean isLock = multiLock.tryLock();
if (isLock) {
    try {
        // 执行核心业务...
    } finally {
        // 4. 释放联锁 (内部会依次释放各个节点的锁)
        multiLock.unlock();
    }
}

学习总结

  • 单点故障与主从同步延迟是 Redis 分布式锁在极致高可用要求下的最后隐患。
  • MultiLock (联锁) 通过在多个独立节点上同时建立锁的冗余备份,用极小的性能牺牲,换取了金融级的强一致性保障。