分布式锁怎么加
分布式锁的标准加锁方式是单条命令 SET 键 唯一值 NX PX 毫秒:一次操作同时完成「不存在才创建」与「过期自动释放」两件事,避免了先判断再设置之间的竞态。值用唯一标识,比如请求编号或机器加线程加时间戳,释放时先校验这个标识再删除,防止误删别人的锁。
基本信息
| 语法 | SET lock:资源 唯一标识 NX PX 毫秒 |
|---|---|
| 唯一标识 | 请求编号或机器线程时间戳组合,释放时校验 |
| 成败判断 | 返回 OK 表示加锁成功,返回空值表示未拿到 |
| 过期时间 | 建议取业务耗时的数倍,长任务需要续期 |
| 释放方式 | 先校验标识再删除,不能直接删除键 |
| 适用范围 | 单实例可靠,集群部署要按对应方案实现 |
典型使用场景
- 防止同一订单被重复处理:处理前加锁,完成后释放
- 定时任务多副本互斥:只允许一个副本执行
- 库存扣减等关键区间的并发控制
- 缓存重建防击穿:只放一个请求去回源
- 消息重复消费的幂等控制
- 资源池分配:同一资源同一时刻只分配给一个消费者
加锁与观察
加锁与观察
# 加锁:NX 表示不存在才设置,PX 为毫秒级过期
SET lock:order:42 6f1d2c4e NX PX 10000
# 返回 OK 表示拿到锁
# 返回空值 表示别人持有,稍后重试或快速失败
GET lock:order:42 # 查看锁当前的值,调试用
PTTL lock:order:42 # 查看剩余过期时间安全释放思路
安全释放思路
# 释放必须校验持有者标识:只有值等于自己的标识才删除
# 逻辑示意(真实实现用脚本或客户端封装保证比较与删除的原子性)
IF GET lock:order:42 == 6f1d2c4e THEN DEL lock:order:42
# 值不等于自己的标识说明锁已过期并被别人获取,直接删除会误删他人的锁加锁结果读法
| 返回 | 含义 | 处理 |
|---|---|---|
| OK | 成功创建锁,当前请求持有 | 进入临界区,处理完主动释放 |
| 空值 | 键已存在,别人持有锁 | 重试或快速失败,不要长时间阻塞 |
| 剩余过期时间为正 | 持有者尚未超时 | 正常状态 |
| 键不存在 | 锁已释放或已经过期 | 可以重新尝试加锁 |
| 值不是自己的标识 | 锁已被他人获取 | 不要删除,避免误删 |
| 过期时间过短 | 临界区未完成锁就失效 | 需要续期机制或加大过期时间 |
释放锁不能直接删除键:必须校验值是否等于自己的标识,否则任务超时后锁已易主,直接删除会把别人的锁删掉,互斥彻底失效。
唯一标识既用于释放校验也用于排查:把请求编号或线程信息写进值里,出现并发问题时能直接看出是谁持有了锁。
过期时间是锁的安全网:太短会让临界区没执行完就失锁,太长会让故障后长时间无法重新加锁,长任务应在处理过程中按需续期。
加锁使用清单
- 加锁用单条条件写入命令,不要拆成判断加设置两步
- 值必须是唯一标识,释放前必须校验
- 过期时间取业务耗时的数倍并留出重试余量
- 临界区内不要做长时间阻塞操作
- 加锁失败要有明确的退避或失败策略
- 多实例部署时确认锁实现与实例拓扑匹配
单实例方案在主节点故障切换时存在窗口:锁可能已经丢失而业务仍在执行,对一致性要求高的场景要结合业务校验或采用集群共识方案。