08.分布式锁
文章目录
问题: 分布式锁:请说明基于 Redis 实现分布式锁的核心要点(如 SET NX EX 的原子性、锁的唯一标识、过期时间续期等);Redlock 算法解决了什么问题?
👇 点击展开/折叠 面试背诵模板(建议先背这个)
一、单节点 Redis 分布式锁的实现要点
1. 原子性加锁与过期时间
- 核心命令:
SET key value NX EX seconds NX:键不存在时才能设置成功(原子性互斥)EX:设置过期时间(单位秒),防止因客户端崩溃或网络中断导致锁永久占用(死锁)- 错误写法:先
SETNX再EXPIRE(两步非原子,若中间崩溃则锁永不过期)
2. 锁的唯一标识(防止误删)
- 锁的值必须为每个客户端唯一的随机字符串(如
UUID + thread_id) - 释放锁时需先校验 value 是否与当前客户端匹配,匹配才能删除
- 使用 Lua 脚本保证“判断 value + 删除”的原子性:
1 | -- Redis Lua 脚本:保证 get 和 del 原子执行 |
3. 过期时间续期(看门狗机制)
- 业务执行时间可能超过锁的过期时间,导致锁提前释放,其他客户端获得锁,引发并发问题
- 解决方案:客户端启动一个后台线程(看门狗),定期(如每 10 秒)检查业务是否还在执行,若未完成则为锁续期(重新设置过期时间)
- Redisson 客户端内置此机制,默认续期 30 秒
二、Redlock 算法的核心思想与适用场景
为什么需要 Redlock?
单节点 Redis 分布式锁存在单点故障风险:若主节点宕机,锁数据未同步到从节点,此时另一个客户端可在新主节点上加锁成功,导致同一资源被多个客户端同时持有。
Redlock 算法(Redis 官方作者提出)
- 部署多个(通常 5 个)独立的 Redis 节点(无主从复制关系)
- 加锁流程:
- 客户端获取当前时间戳(开始时间)
- 依次向所有节点请求加锁(SET NX EX),使用相同的 key 和 value,每个节点设置超时时间(远小于锁有效期,如 5-10ms)
- 若客户端在过半数节点(N/2 + 1)上加锁成功,且总耗时小于锁有效期,则视为加锁成功
- 若失败,客户端向所有节点发送释放锁请求
解决的问题:
- 容忍部分节点故障(过半数存活即可正常加锁)
- 避免主从切换(异步复制)导致锁丢失的问题,提高分布式环境下的安全性
注意事项与局限性:
- 实际使用场景有限,多数业务中单节点 + 自动续期(Redisson)已足够(如库存扣减、防止重复提交)
- Redlock 实现复杂,且对时钟同步(NTP)敏感,引入额外故障点(如节点间时钟跳跃会导致锁失效)
- 除非对安全性有极高要求(如金融级系统),一般不推荐自行实现 Redlock;单节点 + 合理超时 + 续期是主流方案
三、选型建议与常见陷阱
何时用分布式锁?
- 幂等性接口防重(如订单提交)
- 库存扣减防止超卖
- 定时任务防止重复执行
- 全局唯一 ID 生成(多机器下保证自增字段不冲突)
常见陷阱
- 锁过期时间设置过短:业务还没执行完锁就到期,导致并发冲突。建议预估业务耗时,并启用续期机制。
- 释放锁时未校验 value:导致释放了其他客户端的锁。务必用 Lua 脚本校验。
- 未处理 Redis 节点故障:单节点模式可能因宕机导致整个分布式锁不可用。可考虑主从 + 哨兵,或使用 Redlock(但增加复杂度)。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 LGQ的博客!