分布式锁到底怎么用才安全?我对 Redis + Lua 的正确打开方式

27 阅读1分钟

很多后端工程师觉得“加个 Redis 锁”就安全了,其实绝大部分用法都不正确,会导致:

  • 锁提前释放
  • 业务误判
  • 多实例同时执行

这篇文章讲一下我实施过最安全、最常用的 Redis 分布式锁方案。


一、常见错误用法

SET key value NX EX 30

然后执行完:

DEL key

问题:

  • 如果业务超时超过 30s?锁过期提前释放
  • 删除时没有判断 value 是否匹配 → 可能删了别人持有的锁

二、正确用法:value 作为 token

const token = uuid()
SET lock token NX PX 30000

执行完释放锁:

-- Lua 脚本保证原子性
if redis.call("get", KEYS[1]) == ARGV[1] then
  return redis.call("del", KEYS[1])
else
  return 0
end

Node.js 写法:

redis.eval(luaScript, 1, key, token)

三、锁续期机制(Watchdog)

业务超过 30s 怎么办?需要续期线程:

  • 在锁快过期前(如 20 秒)
  • 自动执行 PEXPIRE

例如:

setInterval(() => {
  redis.pexpire(key, 30000)
}, 20000)

四、哪种场景必须使用分布式锁?

  • 秒杀库存扣减
  • 同一业务只允许一个实例执行(如报表生成)
  • 限制用户频繁操作
  • 防重入

五、总结

安全分布式锁必须满足:

  1. 互斥
  2. 不丢锁
  3. 不误删
  4. 可续期
  5. 自动释放

Redis + Lua + Token 的方案是目前最稳的方式之一。