Redis锁到底咋保证能自动过期,防止死锁的那些事儿
- 问答
- 2025-12-26 01:38:10
- 2
关于Redis锁如何保证能自动过期,防止死锁这件事,咱们得从一个最简单的场景说起,想象一下,你要去一个只有一个隔间的公共卫生间上厕所,为了保证隐私,你进去后会把门从里面锁上,这其实就是“加锁”,但如果有人在里面突然晕倒了,或者干脆忘了出来,那这个卫生间就永远没法被其他人使用了,这就形成了“死锁”。
Redis锁解决这个问题的核心思路,就是给这把锁加一个“有效期”,就像你去一些商场卫生间,那个门锁从里面锁上后,超过15分钟它会自动弹开,以防里面的人发生意外,在Redis里,这个“有效期”就是通过一个叫做“过期时间”的特性来实现的。
具体是怎么做的呢?根据Redis官方文档和社区普遍实践,最经典的方法就是使用SET命令的一个特殊参数,以前人们可能会先用SETNX命令去设置一个键(key)来表示锁,然后再用EXPIRE命令给这个键设置过期时间,但这里有个大问题:这两个操作是分开的,不是原子性的,啥叫原子性?就是说这两个命令必须要么都成功,要么都失败,如果刚执行完SETNX,程序就因为某种原因崩溃了,没来得及执行EXPIRE,那么这个锁就永远不会被释放,死锁就发生了。
现在大家普遍采用Redis 2.6.12版本之后支持的更强大的SET命令,这个命令可以一口气完成设置值和设置过期时间两件事,它的语法类似于SET lock_name my_unique_value NX PX 30000,咱们来拆解一下:
lock_name:就是锁的名字,order_123_pay_lock”,表示订单123的支付锁。my_unique_value:这是一个非常关键的部分,它必须是唯一的值,通常是一个随机字符串或者UUID,为啥要唯一?这是为了防止误删别人的锁,比如你加锁后执行时间超过了过期时间,锁自动释放了,然后别人又加锁成功了,这时候如果你直接用DEL命令去删除lock_name这个键,就会把别人的锁给删掉,删除前要判断这个值是不是自己当初设置的那个。NX:意思是“Only set the key if it does not already exist”,只有这个锁不存在的时候,我才能设置成功,也就是加锁成功,如果已经存在,那我就加锁失败,需要等待或重试。PX 30000:这就是咱们说的“自动过期”的秘密所在,它表示这个键的过期时间是30000毫秒,也就是30秒,30秒后,无论发生了什么,Redis服务器都会自动把这个键删除掉,锁也就随之释放了。
这样一来,就从根本上避免了死锁,即使那个拿到锁的应用程序(比如一个Java服务)在执行业务代码的时候突然宕机了,或者因为网络问题、GC(垃圾回收)导致卡顿,超过了30秒,Redis也会保证这个锁最终会被释放掉,其他人 eventually(还是能获得锁,继续往下执行。
光有自动过期就万事大吉了吗?并不是,这又引出了另一个常见问题:“锁提前过期”的麻烦,你设定的过期时间是30秒,但你的业务逻辑可能因为某些原因(比如调用了外部慢接口、进行了复杂的计算)需要执行40秒,当你还在吭哧吭哧执行到第35秒的时候,Redis已经因为30秒到期而把锁自动释放了,另一个应用程序B成功获取了这把锁,并开始执行业务逻辑,在剩下的5秒里,你的应用程序A和B就会同时操作共享资源(比如扣减库存),导致数据错乱,更可怕的是,在第40秒,你的应用程序A终于执行完了,它浑然不知锁已经不属于自己了,它还按照老规矩,去执行删除锁的指令,结果就是把应用程序B刚加上的锁给删掉了!这又会导致第三个应用程序C可能趁虚而入。
为了解决这个问题,人们又想出了“看门狗”机制,这个机制在一些成熟的Redis客户端(比如Redisson)里都有实现,它的思想是:如果你使用的是可重入锁(一个线程可以多次获取同一把锁),那么客户端在成功加锁后,会启动一个后台线程,这个线程就像一个定时闹钟(看门狗),它会在锁过期时间的三分之一左右(比如10秒后)去检查一下,持有锁的客户端是否还在运行,如果还在运行,它就“续租”这把锁,也就是重新把锁的过期时间再设置为30秒(重新计时),这样,只要应用程序没有宕机,并且业务逻辑没有执行完,这个看门狗就会不断地给锁续期,防止它因为执行时间过长而提前过期,一旦业务逻辑执行完毕,客户端会主动释放锁,并通知看门狗线程停止续租,如果应用程序真的宕机了,看门狗线程自然也跟着停了,续租行为中止,锁最终还是会因为过期而自动释放,依然不会造成永久性的死锁。
总结一下,Redis锁保证自动过期、防止死锁,主要依靠两个核心点:
第一,使用具备原子性设置值和过期时间的SET命令,确保在任何情况下,只要锁被成功创建,就一定会有一个倒计时器开始工作,这是防止死锁的安全网。
第二,配合唯一值和可选的看门狗续期机制,来应对更复杂的场景,既防止误删他人的锁,又避免因为业务执行时间长于锁过期时间而带来的数据竞争和锁失效问题,这些都是实践中总结出来的,为了让分布式锁更可靠、更安全的有效方法。

本文由邝冷亦于2025-12-26发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://www.haoid.cn/wenda/68501.html
