"Redis 能不能做分布式锁"是经典问题,但更重要的是:
- 你知道它哪里不可靠吗?
- 你知道正确的工程边界吗?
你必须记住的 3 句话(面试直出):
- Redis 锁的核心是:原子加锁(SET NX PX)+ 正确释放(校验 owner)+ 过期兜底。
- 真正难的是:业务执行时间不确定,所以要么保证超时足够大,要么做续租,但续租又要考虑宕机与误续。
- Redis 锁解决的是"跨进程互斥",它不等于事务;涉及资金/强一致时要优先考虑数据库/一致性组件。
1. 正确的最小实现:SET NX PX + value=token
加锁目标:
- 只有一个客户端能成功
- 持锁者崩溃能自动释放
- 非持锁者不能误删别人的锁
最小正确姿势:
- 加锁:
SET lockKey token NX PX 30000 - 解锁:Lua 脚本做"先比 token 再删 key"(保证原子性)
Lua 解锁脚本的最小形态(你至少要能讲出"compare-and-del"这个原子性):
lua
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end
token 怎么设计更靠谱:
- 以"请求级唯一"作为 owner(例如
uuid + 业务key),不要只用线程 id(跨进程无意义) - 关键是:持锁者能证明"我是我",而不是 token 多复杂
你要能说出:
- 为什么不能
DEL lockKey直接删?- 因为可能删掉别人的锁(锁过期后被别人拿到)。
2. 过期时间:不是越短越好
常见误区:
- TTL 设置太短,业务还没做完锁就过期了 -> 并发进入临界区
合理策略:
- TTL 要覆盖"P99 执行时间 + 抖动"
- 必要时做续租
3. 续租(Watchdog):解决长任务,但会引入新的边界
续租的目标:
- 持锁者还活着且还在执行,就延长 TTL
风险点:
- 续租线程如果失控(例如卡死/网络抖动),可能造成锁释放延迟
- 续租必须确保是"同一个 token 的持锁者"才能续(避免误续)
工程口径:
- 续租是"降低误并发"的手段,不是强一致保证。
4. 可重入:用 owner + 计数实现
要点:
- token 需要能表达 owner(线程/请求/实例)
- 需要计数(重入次数)
- 解锁次数要匹配
常见实现:
- 用 Hash 结构记录 owner -> count
5. Redlock:能讲清"它解决了什么/没解决什么"就够了
Redlock 目标:
- 在多 Redis 节点上获取多数派锁,提高单点故障下的安全性
争议点(面试别硬抬杠,讲边界):
- 网络分区、时钟漂移、客户端暂停(GC/Stop-the-world)等情况下,仍可能出现复杂边界
落地建议:
- 大多数业务场景:单 Redis + 正确 token 校验 + TTL + 续租 + 幂等重试 已足够
- 强一致/强安全:优先 ZK/etcd 或数据库层方案
6. 常见坑(线上真会出事)
-
坑 1:锁过期导致并发进入
- TTL 太短或任务抖动大。
-
坑 2:误删别人锁
- 未校验 token,直接 DEL。
-
坑 3:锁粒度太粗
- 一个 key 锁住全业务,吞吐下降。
-
坑 4:临界区不可幂等
- 锁并不能保证"永远不重入",一定要让关键操作幂等。
更工程化的一句话:
- 锁是"降低并发概率",幂等/状态机/唯一约束才是"把最终结果做对"。
7. 线上排查:为什么"锁明明加了还出并发"
先按这个顺序排:
- 是否用的是
SET NX PX(是否原子) - 解锁是否 Lua 校验 token
- TTL 是否覆盖 P99(是否会提前过期)
- 是否存在 GC/线程暂停导致"实际执行时间远超预期"
常见现象:
- 少量请求偶发双写/重复扣减
- 日志显示两个实例在同一时间处理同一业务 key
工程修复:
- 增大 TTL + 续租
- 临界区幂等(唯一约束/状态机)
- 锁粒度按业务 key 分段
8. 自测清单(你要能顺口讲出来)
-
Q:Redis 锁为什么要 token?
- A:为了释放时校验 owner,避免锁过期后误删别人的锁。
-
Q:为什么 TTL 不是越短越好?
- A:太短会导致业务未完成锁就过期,并发进入临界区。
-
Q:Redis 锁能保证强一致吗?
- A:不能;它是互斥手段,仍需幂等与一致性兜底,强一致场景优先用一致性组件。
9. 30 秒背诵稿
Redis 分布式锁的正确核心是 SET NX PX 原子加锁、value 用 token 标识 owner,并用 Lua 脚本校验 token 后再删保证原子释放,同时用过期时间做崩溃兜底。难点在于业务耗时不确定,TTL 太短会导致锁过期并发进入,因此需要合理 TTL 或续租,同时临界区必须做幂等。Redlock 通过多数派提升容错,但仍有网络分区与暂停等边界,强一致场景更应优先选择 ZK/etcd 或数据库方案。