Redisson 分布式锁复习总结
一、 为什么需要 Redisson?(基于 setnx 的问题)
手动实现的 setnx 锁存在四大痛点,Redisson 逐一解决:
| 痛点 | 描述 | Redisson 解决方案 |
|---|---|---|
| 不可重入 | 同一个线程无法多次获取同一把锁,导致嵌套调用死锁。 | Hash 结构存储计数器,支持同一线程多次加锁。 |
| 不可重试 | 获取锁失败直接返回,无重试机制。 | tryLock 方法支持等待时间,内部通过订阅与自旋实现重试。 |
| 超时释放 | 业务执行时间 > 锁过期时间,导致锁自动释放,安全隐患。 | WatchDog(看门狗)机制,自动续期,默认每 10s 续约至 30s。 |
| 主从一致性 | 主节点写入锁后宕机,未同步到从节点,导致锁丢失。 | MultiLock(联锁),将多个 Redis 节点视为独立节点,须全部加锁成功。 |
二、 快速入门与基本使用
1. 依赖与配置
xml
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.6</version>
</dependency>
java
@Configuration
public class RedissonConfig {
@Bean
public RedissonClient redissonClient(){
Config config = new Config();
config.useSingleServer().setAddress("redis://192.168.150.101:6379").setPassword("123321");
return Redisson.create(config);
}
}
2. 核心代码模板
java
RLock lock = redissonClient.getLock("lock:order:" + userId);
// 尝试获取锁
// boolean isLock = lock.tryLock(); // 无参:立即返回
boolean isLock = lock.tryLock(1, 10, TimeUnit.SECONDS); // 有参:等待1s,锁自动释放10s(WatchDog失效)
if (isLock) {
try {
// 执行业务逻辑
} finally {
lock.unlock(); // 释放锁
}
}
三、 核心原理:可重入锁
1. 实现原理
Redisson 放弃了 setnx 的简单 String 结构,改用 Redis Hash 结构。
- Key :锁名称(如
lock:order:1) - Field :线程标识(
UUID + ThreadID) - Value:重入次数(计数器)
2. Lua 脚本逻辑 (加锁)
Redisson 使用 Lua 脚本保证原子性:
- 锁不存在 :创建 Hash,
hset字段值为 1,设置过期时间。返回null(成功)。 - 锁存在且是自己 :
hincrby将计数器 +1,重置过期时间。返回null(成功)。 - 锁存在但不是自己:返回锁的剩余生存时间(失败)。
3. 解锁逻辑
- 将计数器
-1。 - 若计数器
> 0:说明还有重入,保留锁,重置过期时间。 - 若计数器
<= 0:删除 Key,发布解锁消息。
四、 进阶原理:锁重试与 WatchDog
1. WatchDog (看门狗机制)
目的:解决业务执行时间过长导致锁超时释放的问题。
- 触发条件 :调用
lock()或tryLock()不带 LeaseTime 参数时。 - 默认配置 :锁过期时间
30s,检查间隔10s。 - 工作流程 :
- 加锁成功后,启动一个后台定时任务。
- 每隔
10s(过期时间/3)检查锁是否还被当前线程持有。 - 若持有,重置过期时间为
30s(续约)。 - 若线程宕机,看门狗停止,锁等待
30s后自动释放。
2. 锁重试机制
tryLock(waitTime, leaseTime, unit):- 如果设置了
leaseTime,看门狗机制失效,锁会在指定时间后释放。 - 获取失败时,会利用 Redis 的 Pub/Sub(发布订阅) 机制等待锁释放通知,而不是纯粹的死循环自旋(性能更优)。
- 如果设置了
五、 高可用原理:MultiLock (联锁)
1. 问题背景
在 Redis 主从架构中:
- 客户端向 Master 写入锁。
- Master 宕机,数据未同步到 Slave。
- Slave 升级为新 Master,锁数据丢失。
- 其他客户端成功获取锁,导致并发安全问题。
2. MultiLock 解决方案
原理:放弃主从一致性,将多个 Redis 节点视为独立的 Master。
- 加锁时:必须向所有节点都发送加锁请求,全部成功才算加锁成功。
- 容错性:只要有任意一个节点存活,锁就不会丢失(类似 CP 模型)。
代价:性能下降(需要连接多个节点并发写入)。
六、 复习口诀
- 重入:Hash 结构存 ID,计数加减保原子。
- 续约:看门狗,定时跑,十秒一刷三十秒。
- 重试:消息订阅等通知,避免空转耗资源。
- 高可用:主从同步怕宕机,联锁多写保安全。
