0. 前言
我们完成了计算机底层、Linux高并发、手写Web服务器、内核调优、Redis高性能架构、缓存三大故障防护体系的完整闭环。在上一篇文章中,我们彻底搞定了缓存穿透、击穿、雪崩三大线上核心问题,补齐了Redis缓存工程化落地的所有短板。
今天我们正式攻坚Redis在分布式场景下的核心王牌能力——分布式锁。
分布式锁是后端面试必考、最容易踩坑、区分初级与高级工程师的重难点技术。绝大多数开发者只会手写简单的SET NX EX裸锁,却完全不懂底层致命漏洞:
❌ 锁超时误释放,导致并发冲突
❌ 业务超时执行完毕,锁提前过期
❌ 主从异步复制失效,锁直接穿透
❌ 不可重入导致的死锁问题
❌ 无锁续约,长业务直接失效
市面上90%的博客只教怎么写锁,不教锁的漏洞修复、不讲解工业级落地标准、不剖析Redisson底层原理。
本篇文章从零开始,从原生裸锁逐步迭代到Redisson源码级最优解,层层拆解所有分布式锁痛点、底层成因、解决方案,带你彻底吃透工业级分布式锁,吊打90%面试者的浅层回答!
1. 前置认知:为什么需要分布式锁?
1.1 单机锁的局限性
我们在前面高并发章节学过的synchronized、ReentrantLock、互斥锁、条件变量,全部都是单机锁。
单机锁仅能控制同一进程内多线程的并发竞争,无法解决多服务器、多进程、分布式集群场景下的资源竞争问题。
1.2 分布式锁核心定义
在多节点部署的分布式集群中,保证同一时刻只有一个客户端可以抢占并执行临界业务,统一跨节点的并发竞争规则,实现分布式场景下的线程安全。
1.3 工业级分布式锁四大硬性标准
一把合格的分布式锁,必须同时满足四个条件(面试满分核心):
1.互斥性:同一时刻仅一个客户端加锁成功,核心基础;
2.防死锁:客户端宕机、异常退出时,锁必须自动释放,不阻塞后续业务;
3.防误删:客户端只能释放自己加的锁,不能误删别人的锁;
4.高可用:Redis集群故障、主从切换时,锁机制不彻底失效。
所有原生手写裸锁,全部无法同时满足以上四条标准,存在致命线上漏洞。
2. 版本一:原生错误锁(全网烂大街写法)
2.1 实现逻辑
很多初学者最早接触的分布式锁写法:先判断key是否存在,不存在则set key加锁,业务执行完成后del删除锁。
// 伪代码 if(redis.get("lock") == null){ redis.set("lock", "1"); // 执行业务逻辑 redis.del("lock"); }2.2 致命漏洞(面试必问)
核心问题:非原子操作,极端场景直接并发失效。
get判断和set加锁是两步独立命令,高并发多节点场景下,多个客户端同时get判断为空,会同时执行set加锁成功,彻底丧失互斥性,引发超卖、数据错乱、并发覆盖问题。
同时客户端宕机后锁无法释放,直接永久死锁,业务彻底阻塞。
结论:该写法线上绝对不能用,属于面试扣分重灾区。
3. 版本二:基础原子锁(SET NX EX 初步优化)
3.1 优化方案
利用Redis原子命令SET key value NX EX timeout,将判断+赋值合并为一步原子操作,彻底解决并发覆盖问题,同时设置过期时间防死锁。
NX:key不存在才设置,保证互斥;
EX:设置秒级过期时间,客户端宕机自动释锁。
// 伪代码 // 原子加锁 redis.set("lock", "1", "NX", "EX", 30); // 执行业务 redis.del("lock");3.2 解决的问题
1. 原子操作,杜绝并发加锁失效问题,保证互斥性;
2. 过期时间兜底,客户端宕机自动解锁,解决死锁问题。
3.3 依然存在两大致命漏洞
漏洞一:锁超时误释放(最经典线上事故)
锁过期时间设置30秒,若业务执行耗时超过30秒,锁会被Redis自动释放。此时新客户端成功加锁执行业务,旧客户端业务执行完毕后,直接del删除新客户端的锁,导致锁误释放、并发错乱。
漏洞二:无身份校验,任意客户端可删锁
所有客户端删除的是固定key,无归属校验,任何节点都能随意删除锁,完全不满足工业级安全性。
4. 版本三:身份标识锁(解决误删漏洞)
4.1 优化思路
加锁时存入唯一随机UUID作为身份标识,删除锁时先查询value,校验是自己的UUID再删除,杜绝跨客户端误删锁问题。
4.2 伪代码实现
String uuid = UUID.randomUUID().toString(); // 原子加锁 redis.set("lock", uuid, "NX", "EX", 30); // 业务执行完毕 if(uuid.equals(redis.get("lock"))){ redis.del("lock"); }4.3 新的致命问题:删除锁非原子
get校验和del删除是两步操作,存在时间窗口漏洞:
客户端A校验UUID匹配完成,准备执行删除;此时锁刚好超时自动释放,客户端B成功加锁。紧接着客户端A执行del,直接删除客户端B的有效锁,并发安全彻底失效。
核心痛点:查询+删除非原子,依然存在极小概率误删漏洞。
5. 版本四:Lua脚本锁(实现完全原子操作)
Redis支持Lua脚本,多条命令可在服务端一次性原子执行,中间不会被其他命令插入,彻底解决删锁非原子问题,是手写分布式锁的最优基础版本。
5.1 Lua原子删锁脚本
-- 原子校验并删锁 if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end5.2 当前版本已解决的问题
✅ 原子加锁,保证互斥性
✅ 过期时间兜底,杜绝死锁
✅ UUID身份校验,杜绝随意删锁
✅ Lua原子删锁,彻底封堵时间窗口漏洞
5.3 依然无法解决的两大工业级难题
难题一:锁超时续期问题
业务执行时间不确定,短业务没问题,长业务必然触发锁超时释放,导致业务执行中锁失效,并发安全被打破。手动预估过期时间无法适配所有业务场景,设置过长又会引发死锁风险。
难题二:主从集群锁失效漏洞(红锁问题)
Redis主从架构是异步复制,主节点加锁成功后,数据未同步到从节点时主节点宕机,从节点升级为主节点。新主节点无锁数据,其他客户端可直接加锁成功,分布式锁彻底失效,引发严重并发事故。
这是手写锁永远无法解决的架构级漏洞,必须依赖工业级框架Redisson解决。
6. 工业级最优解:Redisson分布式锁源码级精讲
Redisson是目前Java生态中唯一生产级可用的Redis分布式锁框架,完美解决上述所有漏洞,实现了可重入、自动续期、防误删、防死锁、高可用的标准分布式锁。
6.1 Redisson核心四大优势
1.可重入锁:同一线程可多次加锁,杜绝递归死锁;
2.看门狗自动续期:解决长业务锁超时问题;
3.Lua全程原子操作:加锁、解锁、续期全部原子执行;
4.主从/红锁机制:修复集群锁失效漏洞。
6.2 可重入锁底层原理
原生锁全部不可重入,同一线程递归加锁直接死锁。Redisson采用Hash结构存储锁信息:
- key:锁名称
- field:线程唯一ID
- value:加锁次数(可重入计数器)
同一线程再次加锁,计数器+1,解锁计数器-1,计数器归0才真正释放锁,完美实现可重入特性。
6.3 核心灵魂:看门狗自动续期机制(重点)
所有手写锁最大的短板就是无法自动续期,而看门狗是Redisson的核心精髓。
6.3.1 机制原理
加锁成功后,Redisson会启动一个后台异步定时线程(看门狗),默认每10秒检测一次锁状态:
- 如果当前线程持有锁、业务未执行完毕,自动重置锁过期时间为30秒;
- 业务执行完毕,主动释放锁,看门狗停止任务。
6.3.2 彻底解决的问题
彻底根治业务执行时间不确定导致的锁超时失效问题,无需开发者手动预估过期时间,适配所有长短业务,兼顾安全性与可用性。
6.3.3 面试高频追问
问:看门狗默认时间为什么是10秒续期、30秒过期?
答:采用三分之一阈值设计,保证两次续期间隔内业务必然未执行完毕,预留充足容错时间,杜绝续期不及时导致的锁失效,是工业级成熟容错设计。
6.4 Redisson解锁底层流程
1. Lua原子校验当前线程是否持有锁;
2. 持有锁则可重入计数器减1;
3. 计数器归0,彻底删除锁key,停止看门狗续期任务;
4. 无锁则直接返回,杜绝误删、误释放。
7. 终极面试难点:Redis主从锁失效 & 红锁方案
7.1 主从锁失效底层漏洞
Redis主从复制是异步复制,存在数据同步延迟:
1. 客户端在主节点加锁成功,返回加锁结果;
2. 锁数据尚未同步到从节点,主节点突然宕机;
3. 哨兵机制将从节点晋升为新主节点;
4. 新主节点无锁数据,其他客户端直接加锁成功;
结果:两把锁同时生效,分布式锁彻底失效,并发安全崩塌。
7.2 终极解决方案:Redisson红锁(RedLock)
针对主从异步复制漏洞,Redis官方提出红锁机制,Redisson完美落地:
1. 部署奇数个独立Redis主节点集群(5个/7个);
2. 客户端同时向所有节点发起加锁请求;
3.超过半数节点加锁成功,才算整体加锁成功;
4. 解锁时同步释放所有节点锁。
7.3 红锁适用场景与取舍
优点:彻底解决主从架构锁失效问题,实现极致高可用,适合金融、交易、秒杀等零容错核心业务。
缺点:部署成本高、加锁性能略低,需要多节点冗余。
工业级最佳实践:普通业务使用Redisson可重入锁,金融核心、高并发秒杀业务启用红锁兜底。
8. 分布式锁所有版本迭代总结(面试必背)
1.普通判断锁:非原子、并发失效、死锁风险,彻底废弃;
2.SET NX EX裸锁:解决原子与死锁,存在超时误删漏洞;
3.UUID身份锁:解决误删,删锁非原子仍有漏洞;
4.Lua脚本锁:实现全程原子,无法解决长业务超时、主从失效;
5.Redisson可重入锁:工业级通用方案,自动续期、可重入、原子安全;
6.Redisson红锁:金融级高可用方案,解决主从锁失效终极漏洞。
9. 高频面试满分问答
9.1 为什么不能用Zookeeper做分布式锁,一定要用Redis?
Redis基于内存操作、加锁解锁性能极高、适配高并发场景;Zookeeper基于临时节点、通知机制,性能较低,适合低并发高一致性场景。互联网高并发业务优先Redis分布式锁。
9.2 Redisson看门狗原理是什么?可以关闭吗?
看门狗是后台定时续期线程,默认每10秒续期,保证长业务锁不失效;可以手动关闭,手动指定过期时间后看门狗失效,适合固定短业务场景。
9.3 分布式锁最大的漏洞是什么?如何解决?
普通主从架构最大漏洞是异步复制导致锁失效,常规解决方案无法修复;核心业务采用Redisson红锁机制,过半节点加锁成功,彻底规避主从切换漏洞。
9.4 可重入锁的实现核心?
基于Hash结构存储线程ID与加锁计数器,同一线程累加计数,逐级解锁,实现线程内可重入,杜绝递归死锁。
10. 全文总结
今天我们完成了Redis分布式锁从入门到工业级落地的全链路攻坚。
不再局限于手写简单锁的浅层认知,而是层层迭代、逐个排坑、溯源底层漏洞,彻底搞懂:
✅ 原生锁所有致命缺陷与底层成因
✅ Lua原子脚本的核心作用
✅ Redisson可重入锁、看门狗续期核心原理
✅ 主从架构锁失效的行业级难题
✅ 红锁高可用终极解决方案
至此,我们完整吃透了Redis底层架构、持久化、缓存三大问题、分布式锁全套核心体系,覆盖99%的Redis面试与线上实战场景!