卡码笔记-最强八股文
首页
计算机基础
C++
Java
Go
大模型
  • Java面经
  • C++面经
  • 大模型面经
简历专栏
代码随想录 (opens new window)
首页
计算机基础
C++
Java
Go
大模型
  • Java面经
  • C++面经
  • 大模型面经
简历专栏
代码随想录 (opens new window)
  • 操作系统

  • 网络

  • 数据库

    • SQL

    • 索引

    • 锁与MVCC

    • 事务

    • Redis

      • Redis常见的数据结构
      • Redis缓存淘汰策略
      • Redis过期策略
      • Redis持久化机制:RDB和AOF
      • 缓存雪崩、穿透、击穿
      • Redis分布式锁
        • 简要回答
        • 详细回答
        • 知识图解
        • 代码示例
        • 知识扩展
      • Redis布隆过滤器
      • Redis主从同步
    • 其他

# Redis的分布式锁怎么实现?

# 简要回答

  • Redis 分布式锁本质上就是利用 Redis 的原子命令,让多个服务实例去竞争同一把“全局锁”,最常见的加锁方式是 SET lockKey requestId NX PX 30000。
  • Redis 分布式锁解决四个问题,分别是加锁原子性、锁自动过期、防误删以及业务超时后的续期。在释放锁时最好不要直接 DEL,而要先比对 value 再删除,通常用 Lua 脚本保证原子性。
  • Redis 分布式锁适合做高性能协调,尤其是在主从切换、网络抖动、业务执行过长等场景下。

# 详细回答

  1. Redis 分布式锁
    • 分布式锁被应用在分布式系统里,同一时刻只允许一个客户端执行某段临界业务,比如扣减库存、生成唯一任务、定时任务抢占执行权等。和 JVM 内部的 synchronized、ReentrantLock 不同,Redis 分布式锁是跨进程、跨机器生效的,所以常用在多服务实例部署的场景。
  2. Redis 分布式锁的使用
    • 最常见的方式是:
      SET lock_key requestId NX PX 30000
    • 这里的几个关键点分别是:
      1. NX:只有 key 不存在时才设置成功,可以保证只有一个客户端拿到锁。
      2. PX / EX:给锁设置过期时间,避免客户端异常退出后锁永远不释放。
      3. requestId:每个客户端生成唯一值,表示“这把锁是谁加的”,比如 UUID、请求 ID、线程 ID 组合值。这样在释放锁时才能做归属校验,避免误删别人的锁。
    • SET NX PX把“加锁”和“设置过期时间”合成了一个原子操作。
  3. 释放锁操作
    • 假设线程 A 拿到锁,业务执行时间过长,锁先过期了;这时线程 B 成功拿到同名锁。如果线程 A 此时执行完,直接 DEL lockKey,删掉的就可能是线程 B 的锁,导致两个线程同时进入临界区。
    • 因此,释放锁时要做“先比对 value,再删除”的原子操作,通常用 Lua 脚本:先 GET lockKey,然后判断值是否等于自己的 requestId,如果相等才进行 DEL。
  4. 处理业务超时
    • 如果锁超时时间设置太短,业务还没执行完锁就过期了,别的线程就可能重新拿到锁。为了避免这种情况,常见做法有两类:如果业务可预估,就直接设置一个足够覆盖业务执行时间的 TTL。业务不可预估时可以引入自动续期机制,比如 Redisson 的 watchdog,在业务还没结束时定期延长锁时间。
  5. 常见错误情况
    • SETNX** 和 EXPIRE 分两步执行**:如果 SETNX 成功后服务突然挂掉,还没来得及执行 EXPIRE,锁就会变成死锁。
    • 锁时间设置不合理:TTL 太短会提前过期,TTL 太长又会放大故障恢复时间。
    • 获取锁失败后疯狂自旋:大量线程高频重试会把 Redis 打出额外压力,通常要配合退避重试或快速失败。
  6. 实际开发中,需要根据需求选择合适的实现方式:如果只需要简单互斥控制:可以用单 Redis + 唯一 value + Lua 释放;需要可重入、自动续期、看门狗,则优先使用 Redisson 这样的成熟实现。如果强一致要求极高:不要只盯着 Redis 命令本身,要从业务容错和一致性要求反推锁方案。

# 知识图解

  1. Redis 分布式锁的关键环节
环节 核心做法 目的
加锁 SET key value NX PX ttl 保证“只在不存在时设置”且自动过期
锁标识 每次加锁都生成唯一 requestId 区分锁归属,避免误删
释放锁 Lua 比对 value 后再 DEL 保证校验和删除的原子性
续期 watchdog / 定时延长 TTL 避免业务未完成锁先过期
  1. Redis分布式锁示意图

# 代码示例

SET lock_key request-uuid-001 NX PX 30000

# 安全释放锁:值匹配才删除
EVAL "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" 1 lock_key request-uuid-001
1
2
3
4

# 知识扩展

  1. 面试官可能追问:
  • Q1:为什么不推荐 SETNX 成功后再单独 EXPIRE?
    • 因为这两个操作不是原子的。如果 SETNX 成功后进程挂了,EXPIRE 没执行,锁就可能永远不释放。
  • Q2:为什么释放锁一定要校验 value?
    • 因为锁可能已经过期并被别人重新获取。如果不校验归属,当前线程就可能误删别人的锁。
  • Q3:Redis 分布式锁能保证 100% 绝对安全吗?
    • 不能。尤其是主从异步复制场景下,主节点刚加的锁来不及同步就故障切换,理论上可能出现锁丢失和重复加锁。
  • Q4:Redisson 的 watchdog 解决了什么问题?
    • 它解决的是“业务执行时间不可预估,锁可能提前过期”的问题。只要持锁线程还活着,watchdog 就会继续帮你续期。
Last Updated: 4/30/2026, 11:54:17 AM

← 缓存雪崩、穿透、击穿 Redis布隆过滤器 →

评论

验证登录状态...

侧边栏
夜间
卡码简历
代码随想录
卡码投递表🔥
2026群
添加客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记
鼓励/支持/赞赏Carl
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪