Redis 分布式锁与 Redisson 看门狗

📅 2026/7/13 21:37:18
Redis 分布式锁与 Redisson 看门狗
一句话Redis 分布式锁的核心是用SET key value NX EX seconds原子加锁用唯一 value 标识锁持有者用 Lua 脚本原子释放锁生产环境常用 Redisson因为它支持可重入锁和看门狗自动续期。1. 分布式锁解决什么问题单机synchronized或ReentrantLock只能锁住一个 JVM 内部的线程。在多实例部署时应用实例 A 应用实例 B 应用实例 C ↓ 同时处理同一个订单 / 同一个库存 / 同一个缓存重建任务这时本地锁无法跨机器生效需要一个所有实例都能访问的公共锁服务。Redis 就经常被用来实现分布式锁。2. 错误写法SETNX EXPIRESETNX lock:order1EXPIRE lock:order30问题是两条命令不是原子操作线程 A 执行 SETNX 成功 ↓ 还没来得及执行 EXPIRE ↓ 服务宕机 ↓ 锁没有过期时间永远不释放 ↓ 其他线程再也拿不到锁所以不能把加锁和设置过期时间拆开。3. 正确加锁SET NX EXSET lock:order uniqueValue NX EX30含义SET设置 key NX只有 key 不存在时才设置保证只有一个线程抢锁成功 EX 30设置 30 秒过期时间防止服务宕机后死锁 uniqueValue锁持有者唯一标识例如 UUID 线程 ID这是一条原子命令加锁和设置过期时间同时完成。4. 为什么 value 不能写固定值错误示例SET lock:order1NX EX30如果 value 固定释放锁时无法判断这把锁是不是自己的。典型误删场景线程 A 获取锁过期时间 30 秒 线程 A 业务执行太慢超过 30 秒 锁自动过期 线程 B 获取同一把锁 线程 A 执行完直接 DEL lock:order 结果线程 A 把线程 B 的锁删了所以 value 必须是唯一标识释放锁前要先判断 value 是否等于当前线程持有的值。5. 正确释放锁Lua 原子校验 删除释放锁不能简单DEL key而要ifredis.call(GET,KEYS[1])ARGV[1]thenreturnredis.call(DEL,KEYS[1])elsereturn0end为什么必须用 Lua如果先 GET 判断再 DEL 删除是两条命令。 中间锁可能过期并被其他线程重新获取。 此时原线程再 DEL就可能误删别人的锁。 Lua 脚本在 Redis 中作为一个整体执行中间不会插入其他命令 所以能保证“判断身份 删除锁”的原子性。6. Redis 分布式锁仍然有什么问题过期时间不好设置设置太短 业务没执行完锁就过期其他线程进入临界区 设置太长 服务真的宕机其他线程要等很久才能拿锁不适合所有强一致场景Redis 分布式锁适合防重复执行、缓存重建、普通业务互斥。对于金融级强一致仍要结合数据库事务、唯一索引、乐观锁或更强的一致性组件。7. Redisson 做了什么Redisson 是 Redis 官方推荐之外很常用的 Java 客户端封装提供了更完整的分布式锁能力① 可重入锁 同一个线程重复加锁不会死锁 内部记录重入次数 ② 看门狗自动续期 业务没执行完时自动延长锁过期时间 ③ Lua 脚本释放锁 自动做 value 校验避免误删锁 ④ 更接近 Java Lock 的使用方式 RLock lock redissonClient.getLock(lock:order)8. 看门狗机制看门狗解决的是“锁过期时间不好设置”的问题。默认锁过期时间30 秒 续期间隔约 10 秒检查一次 如果业务线程还持有锁把过期时间续回 30 秒 业务执行完 unlock释放锁并停止续期 服务宕机看门狗线程也停止锁最多 30 秒后自然过期流程lock.lock() ↓ Redisson 加锁成功默认 TTL 30s ↓ 业务线程还活着并持有锁 ↓ 看门狗每隔约 10s 续期一次 ↓ 业务执行完 unlock() ↓ 删除锁停止续期注意通常只有加锁时​不手动指定 leaseTime​看门狗才会自动续期。lock.lock();// 有看门狗自动续期lock.lock(10,TimeUnit.SECONDS);// 通常按指定时间过期不走自动续期9. 分布式锁使用注意事项① 加锁要设置过期时间避免死锁 ② value 要唯一避免误删别人锁 ③ 释放锁要用 Lua 原子判断 删除 ④ 锁粒度不要太粗否则并发能力下降 ⑤ 锁内代码要尽量短不要做慢 SQL 或远程长调用 ⑥ finally 中释放锁避免异常导致锁不释放典型代码结构RLocklockredissonClient.getLock(lock:order:orderId);lock.lock();try{// 查询状态、校验、执行业务更新}finally{lock.unlock();}10. 面试高频追问SET NX EX 能保证绝对安全吗它能保证单 Redis 实例上的加锁原子性和自动过期 但不能解决所有分布式一致性问题。 如果 Redis 主从发生故障切换锁还没同步到从节点就切主 可能出现多个客户端都认为自己拿到锁的情况。 普通业务通常可以接受强一致场景要结合数据库约束或更强一致性的方案。Redisson 看门狗会不会导致锁永远不释放正常不会。业务线程还活着并持有锁时才续期unlock 后停止续期。 如果服务宕机看门狗线程也没了锁会在默认 30 秒后过期。面试回答模板“Redis 分布式锁一般用 SET key value NX EX seconds 实现。 NX 保证 key 不存在时才能加锁EX 设置过期时间防止服务宕机后死锁。 这条命令是原子的不能拆成 SETNX 和 EXPIRE。 value 不能写固定值要用 UUID 加线程 ID 这类唯一标识。释放锁时不能直接 DEL 要用 Lua 脚本先判断 value 是不是自己的再删除避免锁过期后误删别人的锁。 生产环境我会优先用 Redisson。它支持可重入锁和看门狗机制如果没有手动指定 leaseTime默认锁 30 秒过期看门狗大约每 10 秒续期一次。业务执行完 unlock 后停止续期服务宕机后看门狗停止锁最多 30 秒后自然释放。”