Skip to content

Redisson分布式锁

分布式锁用于控制多个服务实例同时操作同一份共享资源。例如多个订单服务实例同时处理同一个订单,如果没有并发控制,就可能重复扣库存、重复支付、重复发券。

Redisson 分布式锁基于 Redis 实现,并通过 Lua 脚本、锁标识、自动续期等机制提高可用性。

基本流程

mermaid
flowchart TD
    A[线程尝试获取锁] --> B{锁不存在?}
    B -->|是| C[写入锁和线程标识]
    B -->|否| D{是否当前线程持有?}
    D -->|是| E[重入次数加 1]
    D -->|否| F[等待锁释放]
    C --> G[执行业务]
    E --> G
    G --> H[finally 中释放锁]

可重入锁

可重入锁指同一个线程已经拿到锁后,可以再次获取同一把锁而不会被自己阻塞。

典型场景:

java
RLock lock = redissonClient.getLock("order:lock:1001");
try {
    if (lock.tryLock(3, 30, TimeUnit.SECONDS)) {
        // 执行业务
    }
} finally {
    if (lock.isHeldByCurrentThread()) {
        lock.unlock();
    }
}

Redisson 会记录当前锁被同一线程重入的次数。每次 unlock 会让次数减一,直到次数为 0 才真正删除锁。

看门狗续期

mermaid
flowchart TD
    A["业务线程在Redis加锁成功"] --> B["WatchDog注册续期任务"]
    B --> C["业务仍持锁且客户端存活"]
    C --> D["WatchDog按周期校验并续期"]
    D --> C
    C --> E["业务完成后校验所有权并释放"]

如果没有指定锁过期时间,Redisson 默认会通过看门狗续期。这样可以避免业务执行时间超过默认锁时间导致锁提前释放。

但这不代表锁内可以执行无限长任务。锁持有时间越长,系统吞吐越低。

联锁(RedissonMultiLock)

联锁是把多把锁合成一把锁使用。只有所有锁都获取成功,整体才算加锁成功。

适合一个业务操作必须同时锁住多个资源的场景,例如同时锁订单和库存。

mermaid
flowchart TD
    A[尝试获取锁 A] --> B{成功?}
    B -->|否| X[失败返回]
    B -->|是| C[尝试获取锁 B]
    C --> D{成功?}
    D -->|否| E[释放锁 A 后失败返回]
    D -->|是| F[执行业务]
    F --> G[释放锁 A 和锁 B]

注意:联锁会增加失败概率和等待时间,使用前要确认是否真的必须同时锁多个资源。

红锁(RedissonRedLock)

红锁是 Redis 分布式锁的多节点多数派思路:客户端向多个相互独立的 Redis 节点加锁,只要多数节点加锁成功,并且耗时没有超过锁有效期,就认为加锁成功。

mermaid
flowchart TD
    A["客户端生成 token"] --> B["多个独立 Redis 节点加锁"]
    B --> C["统计成功数量"]
    C --> D{"是否达到多数派"}
    D -- "是" --> E["校验加锁耗时"]
    D -- "否" --> F["释放部分锁并失败"]
    E --> G{"耗时是否小于 TTL"}
    G -- "是" --> H["获得红锁"]
    G -- "否" --> F

红锁用于降低单个 Redis 节点故障带来的锁安全问题,但它不是强一致共识算法。普通业务中,单 Redis 锁或 Redisson RLock 加上幂等、状态机和补偿通常更常见;需要理解红锁完整流程、适用边界、Java Demo 和面试回答时,看 Redis 红锁 Redlock

更多扩展能力

Redisson 除了 RLockMultiLock 和红锁,还会在项目里用到公平锁、读写锁、信号量、可过期信号量、闭锁等能力。它们不是为了“显得高级”,而是分别解决顺序等待、读多写少、限制并发数、异常自动回收许可、跨实例流程等待等问题。

mermaid
flowchart TD
    A["Redisson 同步能力"] --> B["RLock 可重入锁"]
    A --> C["FairLock 公平锁"]
    A --> D["ReadWriteLock 读写锁"]
    A --> E["Semaphore 信号量"]
    A --> F["CountDownLatch 闭锁"]
    A --> G["Redlock 多节点多数派"]

完整原理、适用场景和代码 demo 看 分布式锁扩展点

常见风险

锁过期但业务没执行完

如果锁提前过期,其他线程可能拿到锁并发执行。解决方式:

  • 使用看门狗续期。
  • 设置足够合理的 leaseTime。
  • 缩短锁内业务耗时。

误删别人的锁

释放锁时必须校验锁归属。Redisson 内部会用线程标识判断当前线程是否持有锁,避免删除其他线程的锁。

Redis 故障

Redis 锁依赖 Redis 可用性。对资金、库存这类强一致场景,要结合数据库约束、状态机、幂等表、补偿任务一起设计。

使用建议

  1. 加锁粒度尽量小,例如按订单 ID 加锁,不要全局加锁。
  2. 锁内只放必须串行的代码。
  3. 解锁放在 finally
  4. 业务本身仍然要幂等,不能完全依赖锁。
  5. 高并发热点资源要考虑队列化或状态机,避免大量线程争抢锁。