Redis分布式锁及看门狗机制
Redis 分布式锁
在分布式系统中,多个节点可能需要对共享资源进行互斥访问,此时需要分布式锁。Redis 常用于实现分布式锁,其核心实现方式如下:
- 加锁:使用
SETNX
(SET if Not eXists)命令或SET
命令的NX
参数,确保只有当锁不存在时才能设置成功。 - 设置过期时间:通过
EX
参数为锁设置过期时间,防止持有锁的节点崩溃后锁无法释放。 - 解锁:通过 Lua 脚本确保只有锁的持有者才能释放锁,避免误删。
看门狗的工作原理
- 自动续期:
- 当一个线程成功获取锁后,Redisson 会为该锁设置一个初始的有效期(例如 30 秒)。
- 看门狗会启动一个后台线程,定期(通常是锁有效期的一半时间)发送命令给 Redis,以自动延长锁的过期时间。
- 只要持有锁的线程仍在运行且未显式释放锁,锁的有效期将被持续延长。
- 锁释放:
- 当持有锁的线程完成任务后,显式调用
unlock
方法释放锁。 - 释放锁后,看门狗停止续期操作。
- 当持有锁的线程完成任务后,显式调用
- 异常处理:
- 如果持有锁的线程因异常终止,看门狗将不再续期锁的有效期,锁会在其原始过期时间后自动释放,避免死锁。
- 看门狗机制防止的问题
- 锁意外释放
- 在分布式系统中,锁的持有时间可能超过最初设置的过期时间,尤其是在任务执行时间较长或网络延迟较高的情况下。看门狗机制通过定期续期锁的有效期,确保锁不会因为超时而被意外释放。
- 数据不一致
- 如果锁在任务完成前意外释放,其他节点可能会获取到同一个锁并操作共享资源,从而导致数据不一致。看门狗机制通过持续续期锁,确保当前任务完成前其他节点无法获取锁。
- 死锁问题
- 如果持有锁的节点因异常崩溃,看门狗机制会停止续期锁的有效期,锁会在过期后自动释放,从而避免永久性锁住资源。
- 业务逻辑错误
- 在某些场景下,如订单处理系统,任务可能需要较长时间才能完成。看门狗机制可以确保锁在整个任务执行期间保持有效,避免因锁过期而导致任务重复处理。
- 锁意外释放
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class RedissonWatchdogExample {
public static void main(String[] args) {
// 配置 Redisson
Config config = new Config();
config.useSingleServer().setAddress("redis://localhost:6379");
// 设置看门狗超时时间(单位:毫秒)
// 默认值为 30000 毫秒(30秒),这里设置为 60秒
config.setLockWatchdogTimeout(60000);
// 创建 Redisson 客户端
RedissonClient redisson = Redisson.create(config);
// 获取分布式锁
RLock lock = redisson.getLock("myLock");
try {
// 尝试获取锁,看门狗机制会自动续期锁
boolean isLocked = lock.tryLock();
if (isLocked) {
System.out.println("锁获取成功,执行业务逻辑...");
// 模拟业务逻辑执行时间
Thread.sleep(100000); // 100秒
System.out.println("业务逻辑执行完成,释放锁...");
} else {
System.out.println("锁获取失败,已有其他线程持有锁...");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放锁
if (lock.isHeldByCurrentThread()) {
lock.unlock();
System.out.println("锁已释放");
}
}
// 关闭 Redisson 客户端
redisson.shutdown();
}
}