Redis实现分布式锁的演进思路
相关概念:Redis
Redis 分布式锁最容易踩坑的地方,不是“怎么写出第一版”,而是“第一版为什么很快就不够用”。
第一步:只有单机锁不够
如果服务部署在多个 JVM 上,synchronized 只能保护单进程内的线程,挡不住多机并发。
这时才有必要把锁状态放到 Redis 里。
第二步:至少要有超时
最简单的写法,是用 SETNX 一类语义去抢锁,并顺手加上过期时间。
没有过期时间的问题很直接:
- 线程拿到锁后崩了
- 锁永远不释放
- 其他请求全部卡死
第三步:解锁必须有归属校验
只有“谁加的锁,谁才能解”才算像样的分布式锁。
否则一个无关线程误删锁,就会让临界区重新暴露在并发写入下。
常见做法是:
- 加锁时写入线程唯一标识
- 解锁时先比对标识,再决定是否删除
第四步:要考虑可重入
如果同一线程在方法嵌套调用里反复进入临界区,锁需要支持可重入。
不然会出现两类问题:
- 再次加锁失败,导致本线程把自己拦住
- 内层方法提前解锁,导致外层逻辑在无锁状态下继续执行
一个实用思路是:
- Redis 里只保存锁归属
- 线程内再额外维护重入计数
这还不是终点
就算做到了“超时 + 归属 + 可重入”,离生产可用通常还差一截,至少还要继续考虑:
- 解锁是否原子,避免“先判断后删除”被并发穿透
- 业务执行时间超过 TTL 时是否需要续期
- 锁粒度是否过粗
- 主从切换时是否存在锁丢失窗口
结论
Redis 很适合用来理解分布式锁的基本机制,但真正进生产,通常更应该优先用成熟实现,而不是手搓一个“差不多能跑”的版本。