Redis分布式锁实战:正确加锁、续期与释放
正确加锁:SET NX PX 与唯一锁标识
分布式锁的核心是解决多节点并发访问共享资源时的数据一致性问题。在单实例 Redis 中,必须使用 SET key value NX PX milliseconds 命令一次性完成加锁与过期时间设置。旧版 SETNX 与 EXPIRE 分步执行存在竞态条件,若加锁后服务宕机,锁将永久残留。NX 保证仅当键不存在时写入,PX 设定毫秒级自动过期时间,防止死锁。value 必须使用 UUID 或雪花算法生成的唯一随机值,用于标识锁的持有者。操作流程为:客户端生成唯一标识,执行 SET 命令;若返回 OK 则加锁成功,进入业务逻辑;若返回 nil 则加锁失败,可选择短暂休眠后重试或快速失败。例如,设置锁 lock:order:1001,值为 client-uuid-abc123,过期时间 30000ms,即可安全抢占资源。
锁续期:避免业务执行超时导致锁提前失效
固定 TTL 无法精准匹配动态业务耗时。若业务执行时间超过锁的过期时间,锁会被 Redis 自动删除,导致其他客户端误入临界区,引发数据错乱。为此需引入续期机制(Watchdog)。续期逻辑必须严格限定:仅当当前客户端仍持有该锁(即 Redis 中 value 与本地唯一标识一致)时,才允许执行 EXPIRE 延长 TTL。通常采用后台定时任务,在锁剩余 TTL 降至三分之一时触发续期。若续期失败(如 Redis 网络抖动或锁已被抢占),业务线程必须立即停止执行或转入降级流程,绝不能盲目重试。需注意,续期仅是缓解超时压力的辅助手段,无法掩盖业务线程阻塞、死循环或逻辑失控等根本问题。例如,初始 TTL 设为 30 秒,后台线程每 10 秒检查一次,若剩余时间低于 10 秒且持有者校验通过,则重置为 30 秒。

安全释放:Lua 原子校验,避免误删他人锁
释放锁时绝不能直接调用 DEL 命令。由于锁具有自动过期特性,若当前客户端业务执行缓慢,锁可能已过期并被其他客户端成功获取。此时若原客户端直接执行 DEL,将误删他人持有的锁,彻底破坏互斥性。正确的做法是先校验,后删除,且这两步必须保证原子性。推荐使用 Lua 脚本将 GET 与 DEL 封装在单次请求中:脚本首先获取指定 key 的当前 value,与客户端本地保存的唯一标识进行比对;若完全一致,则执行 DEL 并返回成功状态;若不一致或 key 已不存在,则直接返回失败。由于 Redis 单线程执行 Lua 脚本的特性,该过程不会被其他命令打断。例如,传入 key 为 lock:order:1001,预期 value 为 client-uuid-abc123,脚本校验匹配后才执行删除,从而彻底杜绝误删风险。

实战验证与避坑:并发、超时、宕机三类场景
验证分布式锁可靠性需覆盖三类核心场景。首先是并发竞争:启动多个客户端同时请求同一资源,仅应有一个返回加锁成功,其余应进入重试或失败分支。其次是超时场景:模拟业务执行时间大于锁 TTL,观察锁是否按预期自动释放,且后续客户端能否安全重新获取。最后是宕机异常:强制终止持锁进程,验证 Redis 是否依赖 PX 参数自动清理残留锁,确保系统恢复后无死锁。实战中常见错误包括:使用 SETNX 后未设过期时间导致永久死锁;续期时不校验持有者身份引发锁漂移;释放锁时将 GET 校验与 DEL 操作拆分为两次网络请求,产生竞态窗口。需明确,单实例 Redis 方案适用于对可用性要求极高、可容忍极小概率锁丢失的场景;若需强一致性与高可用,应转向 Redlock 算法或基于 ZooKeeper/etcd 的分布式协调服务。

本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













