📌 一、问题引入:一场由 Redis 分布式锁引发的血案

在 Java 分布式系统中,Redis 作为高性能的缓存中间件被广泛用于实现分布式锁。

常见的做法是使用:

SET key value NX PX 30000

来加锁——这段命令的含义是:仅当 key 不存在时设置,并设置过期时间为 30 秒。

但如果你以为这样就安全了,那就大错特错!

❗ 场景还原

  1. 微服务 A 成功获取锁(Redis 主节点写入 lock:order)。
  2. 还未释放,Redis 主节点突然挂了。
  3. Redis 自动发生主从切换,从节点升级为新主。
  4. 新主上未同步 lock:order 锁状态。
  5. 微服务 B 检查无锁,直接抢锁成功!
  6. 💥两个服务都认为自己拥有锁,导致业务并发冲突、数据错乱!

📉 二、为什么会发生这种灾难?

🔍 原因:Redis 主从复制是异步的

Redis 的复制默认是异步:

  • 写入主节点的数据不一定能及时同步到从节点;
  • 主节点宕机后,从节点变主节点;
  • 从节点可能压根不知道锁存在,于是下一个客户端就能再次加锁!

✅ 三、正确姿势一:RedLock 分布式锁算法

📌 RedLock 原理

  1. 将锁请求同时发送到 多个独立的 Redis 节点(建议 5 个)。
  2. 只要在多数节点(如 ≥3)成功加锁,则认为加锁成功。
  3. 锁具有统一的 TTL(过期时间),且加锁过程必须在较短时间(如 500ms)内完成。
  4. 释放锁时必须向所有节点发起解锁请求。

✅ 优势:

  • 不依赖主从复制,避免单节点故障导致锁状态丢失。
  • 即使部分节点挂掉,仍能维持分布式锁正确性。

⚠️ 注意事项:

  • 必须部署多个 独立 Redis 实例(非主从结构);
  • 推荐使用 Redisson 框架封装 RedLock。

💻 四、实战演示:Redisson 实现 RedLock(Java)

1️⃣ 引入依赖

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.27.2</version>
</dependency>

2️⃣ 配置多个独立 Redis 节点(非主从)

Config config = new Config();
config.useClusterServers()
      .addNodeAddress("redis://127.0.0.1:7001")
      .addNodeAddress("redis://127.0.0.1:7002")
      .addNodeAddress("redis://127.0.0.1:7003");
RedissonClient redisson = Redisson.create(config);

3️⃣ 加锁代码(RedLock)

RLock lock1 = redisson.getLock("lock1");
RLock lock2 = redisson.getLock("lock2");
RLock lock3 = redisson.getLock("lock3");

RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);

try {
    boolean isLocked = redLock.tryLock(500, 30000, TimeUnit.MILLISECONDS);
    if (isLocked) {
        System.out.println("加锁成功,执行业务...");
    }
} finally {
    redLock.unlock();
}

✅ 五、正确姿势二:使用 Zookeeper 实现强一致分布式锁

Zookeeper 采用 CP 模型(强一致性),可以使用 Apache Curator 实现分布式锁。

💡 Zookeeper 优势:

  • 天然支持分布式一致性;
  • 容错性高,适用于高可靠场景;
  • 不依赖 Redis,避免缓存误删等问题。

✅ 六、正确姿势三:业务+锁双重保障机制

  • 锁状态记录数据库、MQ 或本地;
  • 锁续命机制避免业务执行过慢导致锁提前过期;
  • 对并发操作增加幂等校验、状态回滚。

❌ 七、常见错误用法警示

错误用法风险点说明
只使用 Redis 主节点加锁主从切换后锁可能丢失
依赖 Redis 异步复制锁数据同步无法保证锁存在
忽略锁过期时间 & 无续命机制业务未完成,锁已被其他线程获得
不使用唯一值标识锁归属锁被误删或误释放

📦 八、最佳实践总结

应用场景推荐方案
高性能 & 高可用Redisson + RedLock
强一致性要求Zookeeper + Curator 分布式锁
简单单机锁Redis 单实例

🔚 九、写在最后:锁不是万能,幂等才是底线

分布式系统中锁只是“安全带”,不能成为系统唯一依赖。正确的做法应该是:

锁 + 幂等 + 补偿机制 + 状态机保障

📥 十、附加福利:RedLock 加锁逻辑图

ClientRedis1Redis2Redis3tryLock(lockKey)SuccesstryLock(lockKey)SuccesstryLock(lockKey)Fail获取多数成功,锁定成功ClientRedis1Redis2Redis3

🚨你还在用 Redis 的单节点锁?别怪主节点挂了导致数据错乱!
点赞 + 收藏 + 关注,一起掌握分布式锁最强姿势🔥!

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐