Redis分布式锁续期机制怎么实现?怎么避免锁失效导致数据丢失和业务中断?

文章导读
Redis 分布式锁续期机制主要通过“看门狗”(Watchdog)实现。当业务执行时间超过锁的过期时间时,看门狗线程会定时检测锁是否仍由当前客户端持有,若是则自动延长锁的过期时间,防止锁提前释放导致并发安全问题。为避免锁失效导致数据丢失,需设置合理的过期时间防止死锁,使用唯一标识(如 UUID)防止误删锁,并利用 Lua 脚本保证加锁解锁的原子性。此外,采用 Redisson 等成熟框架可内置处理
📋 目录
  1. A 使用 Go 语言实现 Redis 分布式锁 (附有看门狗自动续期机制)
  2. B Redis:Redisson 看门狗续锁实现分布式锁的原理,及如何避坑
  3. C 如何使用 Redisson 实现分布式锁?
  4. D Redis 分布式锁源码深度解析:从原理到实现细节
  5. E FAQ
A A

Redis 分布式锁续期机制主要通过“看门狗”(Watchdog)实现。当业务执行时间超过锁的过期时间时,看门狗线程会定时检测锁是否仍由当前客户端持有,若是则自动延长锁的过期时间,防止锁提前释放导致并发安全问题。为避免锁失效导致数据丢失,需设置合理的过期时间防止死锁,使用唯一标识(如 UUID)防止误删锁,并利用 Lua 脚本保证加锁解锁的原子性。此外,采用 Redisson 等成熟框架可内置处理续期逻辑,确保业务完成前锁不失效,同时配合红锁(Redlock)算法可在集群环境下提高可用性,避免主从切换导致锁丢失。

使用 Go 语言实现 Redis 分布式锁 (附有看门狗自动续期机制)

初识分布式锁 Redis 我们日常开发经常使用,而分布式锁的一个重要实现就是通过 Redis 完成,分布式锁要解决的核心问题是防止对某个资源进行重复或者过度请求,例如我们在分布式系统中创建订单之前,必须获取分布式锁才能创建订单,其要解决的主要问题有两个:1) 如果用户重复点击提交订单按钮,可以通过分布式锁避免重复创建订单 2) 商品库存有限,通过分布式锁能够解决超卖问题 而分布式锁的实现也有很多种方法,例如:数据库实现分布式锁 数据库中有行级锁、表级锁等等,这里举一个轻量级的分布式调度框架 xxl-job,它在分布式环境下的调度就是通过获取行级锁,也就是排它锁来实现的:代码语言:sql AI 代码解释 SELECT*FROMxxl_job_lockWHERElock_name='schedule_lock'FORUPDATE; Redis 实现分布式锁 由于 Redis 中 set nx 命令的原子性,只有在键值不存在的时候才能设置值,因此可以通过 set nx 实现分布式锁,但是它有弊端就是:如果业务还没有执行完,那么会导致业务没有执行完,锁就被释放了 因此延伸出了基于 Redis 延伸的 Redisson 分布式锁框架,它实现的原理在于使用 Redis 单线程模型执行 SET NX 命令 lua 脚本确保获取锁操作原子性,同时它内置了更为丰富的看门狗机制,满足了在业务执行过程中,自动续期锁

Redis:Redisson 看门狗续锁实现分布式锁的原理,及如何避坑

Redis 实现分布式锁的要求 1、互斥性; 防止多个进程及线程并发访问共享资源,使得资源串行访问操作。2、设置锁过期时间; 为了防止锁悬挂,因为服务宕机,锁不释放问题,其它请求就无法获取锁。3、自动续锁超时时间; 防止业务超时,超过锁过期时间自动释放,打破互斥性。4、多条指令需要原子性; lua 脚本实现多个指令的加锁、解锁及续锁的原子性。5、可重入性; 使用线程 ID 信息来保证同一线程请求锁的可重入性。6、锁误删:自己把别人持有的锁删了; 多个客户端释放锁,如何防止自己删别人的或者别人删自己申请的锁。获取锁之前,生成全局唯一 id,判断是否是自己的 id 来避免。7、锁等待:发布订阅机制通知等待锁的线程; Redisson 看门狗续锁实现分布式锁 以 RedissonLock 为例来分析 代码语言:javascript AI 代码解释 代码语言:javascript AI 代码解释 的实现。tryLock 方法调用分析:当锁超时时间为 -1 时,而且获取锁成功时,会启动看门狗定时任务自动续锁:每次续锁都要判断锁是否已经被释放,如果锁续期成功,自己再次调度自己,持续续锁操作。为了保证原子性,用 lua 实现的原子性加锁操作

如何使用 Redisson 实现分布式锁?

1.SETNX 存在的问题 虽然可以使用 SETNX 命令方便的实现分布式锁,但是 SETNX 存在以下问题:死锁问题:SETNX 如未设置过期时间,锁忘记删了或加锁线程宕机都会导致死锁,也就是分布式锁一直被占用的情况。锁误删问题:SETNX 设置了超时时间,但因为执行时间太长,所以在超时时间之内锁已经被自动释放了,但线程不知道,因此在线程执行结束之后,会把其他线程的锁误删的问题。不可重入问题:也就是说同一线程在已经获取了某个锁的情况下,如果再次请求获取该锁,则请求会失败 (因为只有在第一次能加锁成功)。也就是说,一个线程不能对自己已持有的锁进行重复锁定。无法自动续期:线程在持有锁期间,任务未能执行完成,锁可能会因为超时而自动释放。SETNX 无法自动根据任务的执行情况,设置新的超时实现,以延长锁的时间。那么如何解决以上这些问题呢?这就是今天要讲的重点 Redisson,使用 Redisson 框架就可以解决以上这些问题了。2. 什么是 Redisson? Redisson 是一个开源的用于操作 Redis 的 Java 框架。与 Jedis 和 Lettuce 等轻量级的 Redis 框架不同,它提供了更高级且功能丰富的 Redis 客户端。它提供了许多简化 Redis 操作的高级 API,并支持分布式对象、分布式锁、分布式集合等特性。

Redis 分布式锁源码深度解析:从原理到实现细节

一、Redis 分布式锁的核心原理 Redis 分布式锁的实现基于其单线程特性和原子性命令,核心原理可以概括为:互斥性:通过 SET NX(仅当键不存在时才设置) 命令保证同一时间只有一个客户端能获取锁 安全性:为锁设置过期时间,避免客户端崩溃导致锁永久无法释放 唯一性:每个客户端获取的锁包含唯一标识,确保只能释放自己持有的锁 原子性:使用 Lua 脚本保证解锁操作的原子性,避免误释放其他客户端的锁 Redis 官方推荐的分布式锁实现方案 (Redlock 算法) 虽然更健壮,但在大多数场景下,基于单 Redis 节点的实现已能满足需求,且实现简单、性能优异。二、核心命令解析 Redis 分布式锁的实现依赖几个关键命令,理解这些命令的行为是掌握分布式锁原理的基础:1. SET 命令的扩展参数 代码语言:javascript AI 代码解释 # 加锁命令 SETlock:resource uuidNXPX30000 NX:仅当键不存在时才设置成功,保证互斥性 PX 30000:设置键的过期时间为 30000 毫秒 (30 秒),避免死锁 uuid:客户端生成的唯一标识,用于解锁时验证身份 该命令的返回值:成功:OK 失败:nil 2. Lua 脚本实现原子解锁 解锁需要先判断锁的持有者是否为当前客户端,再删除锁,这两个操作需要原子性执行

FAQ

为什么简单的 SETNX 命令不足以实现可靠的分布式锁?

Redis分布式锁续期机制怎么实现?怎么避免锁失效导致数据丢失和业务中断?

因为 SETNX 无法自动续期,如果业务执行时间超过锁过期时间,锁会自动释放导致并发问题;且若未设置过期时间,客户端宕机可能导致死锁;此外还存在锁误删和不可重入的问题。

Redisson 的看门狗机制是如何工作的?

当获取锁成功且未指定超时时间时,Redisson 会启动一个定时任务,定期检查锁是否仍由当前客户端持有,若是则自动延长锁的过期时间,直到业务完成或客户端宕机。

如何防止分布式锁被误删除?

在加锁时设置一个唯一标识(如 UUID+ 线程 ID)作为锁的值,释放锁时先判断当前锁的值是否与自己的标识一致,一致才删除,通常使用 Lua 脚本保证判断和删除的原子性。