如何在Redis中使用分布式互斥锁并防范死锁导致的请求击穿?

冬婷小哥_3732

冬婷小哥_3732

2026-10-20

866人浏览

原创

redis分布式锁本身不防击穿和死锁,必须靠业务层协同解决:setnx+expire非原子操作易致死锁;锁值未校验、过期时间不合理或粒度不匹配会引发击穿与误删。

如何在redis中使用分布式互斥锁并防范死锁导致的请求击穿?

Redis 分布式互斥锁本身不防击穿,也不自动防死锁;它只提供基础互斥能力。击穿和死锁必须靠业务层加锁逻辑、超时控制、值校验释放三者协同解决。

为什么 SETNX + EXPIRE 会引发死锁和击穿

常见错误是把 SETNX 和 EXPIRE 拆成两条命令执行。如果 SETNX 成功但 EXPIRE 失败(如网络中断、Redis 写入后主从同步失败),锁就永远不释放——这就是典型死锁源头。同时,这种锁不绑定缓存 key 生命周期,当缓存过期瞬间多个请求都卡在“等锁”阶段,一旦第一个请求写完缓存,后续请求仍可能因锁未释放或重试策略不当而继续穿透数据库。

  • SET key value NX 成功后崩溃,没来得及设过期时间 → 锁永久残留
  • 锁过期时间(如 30 秒)短于业务查询+回填耗时(如 45 秒)→ 锁提前释放,第二个请求抢锁成功,双写数据库
  • 用固定字符串(如 "1")作锁值,DEL lock:key 直接删 → 高并发下极易误删别人持有的锁

必须用 SET 命令原子加锁 + Lua 安全释放

加锁必须一步到位,释放必须带值校验。Redis 的 SET key value NX PX milliseconds 是唯一推荐的加锁入口,它把存在性判断、赋值、过期时间三件事打包成原子操作。

redis-tools
redis-tools

按类别查找Redis命令、检测服务器连接、监控键数量和内存占用,支持离线速查表。

下载
  • 锁值不能写死,要用唯一标识,比如 UUID.randomUUID().toString() + "-" + hostName,避免容器漂移或多实例冲突
  • 释放锁必须用 Lua 脚本,且只在值匹配时才 DEL:if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end
  • 不要用 redisTemplate.opsForValue().setIfAbsent() 单独设值再手动 expire(),Spring Data Redis 的这个方法底层仍是分两步,不可靠

如何防止击穿:加锁不是终点,是缓存重建流程的起点

拿到锁之后,不能直接查库——要先二次检查缓存是否已被其他线程写入。这是“双重检测”(Double-Check)的核心,否则大量请求排队获取锁后,仍会重复查库。

  • 加锁成功后,立刻 GET cache:key,若命中则直接返回,跳过数据库查询
  • 只有缓存确实为空时,才查库、写缓存、再返回;空结果也要缓存(如 SET cache:key "" EX 60),防穿透
  • 锁过期时间必须大于「最坏情况下的查库+序列化+写缓存」耗时,建议按 P99 数据库响应时间 × 2 再上浮 20%
  • 别依赖 Redlock 多节点——它不解决击穿,也不保证锁不丢;单实例 Redis + 正确原子操作 + 合理超时,对缓存重建类场景已足够

看门狗不是可选项,而是生产环境刚需

业务处理时间不可控,锁过期时间又不能无限制拉长。这时候必须引入自动续期机制,也就是“看门狗”。Redisson 的 watchdog 默认每 10 秒检查一次锁剩余时间,若大于 1/3 就自动延长为 30 秒。自己实现的话,需起独立线程监听锁 TTL 并定期 PEXPIRE。

  • 没有看门狗,只要业务慢于锁过期时间,就必然出现“锁失效后多客户端并发写缓存”
  • 看门狗续期必须校验锁值,否则可能给别人的锁续命
  • 注意时钟漂移:Docker 容器或虚拟机时间不同步会导致 PEXPIRE 计算异常,建议宿主机开启 NTP 同步

真正容易被忽略的点是:锁粒度和缓存 key 必须严格对齐。比如锁的是 lock:product:123,那缓存 key 就得是 cache:product:123,不能一个带前缀一个不带,也不能用用户 ID 替代商品 ID 去加锁——否则根本拦不住针对同一资源的并发请求。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

redis

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
什么是分布式
什么是分布式

分布式是一种计算和数据处理的方式,将计算任务或数据分散到多个计算机或节点中进行处理。本专题为大家提供分布式相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2053

5

分布式和微服务的区别
分布式和微服务的区别

分布式和微服务的区别在定义和概念、设计思想、粒度和复杂性、服务边界和自治性、技术栈和部署方式等。本专题为大家提供分布式和微服务相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.07

3134

5

常用的数据库软件
常用的数据库软件

常用的数据库软件有MySQL、Oracle、SQL Server、PostgreSQL、MongoDB、Redis、Cassandra、Hadoop、Spark和Amazon DynamoDB。更多关于数据库软件的内容详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.02

4549

19

内存数据库有哪些
内存数据库有哪些

内存数据库有Redis、Memcached、Apache Ignite、VoltDB、TimesTen、H2 Database、Aerospike、Oracle TimesTen In-Memory Database、SAP HANA和ache Cassandra。更多关于内存数据库相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.14

4095

11

mongodb和redis哪个读取速度快
mongodb和redis哪个读取速度快

redis 的读取速度比 mongodb 更快。原因包括:1. redis 使用简单的键值存储,而 mongodb 存储 json 格式的数据,需要解析和反序列化。2. redis 使用哈希表快速查找数据,而 mongodb 使用 b-tree 索引。因此,redis 在需要高性能读取操作的应用程序中是一个更好的选择。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.02

7612

6

redis怎么做缓存服务器
redis怎么做缓存服务器

redis 作为缓存服务器的答案:redis 是一款开源、高性能、分布式的键值存储,可作为缓存服务器使用。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

643

6

redis怎么解决数据一致性
redis怎么解决数据一致性

redis 提供了两种一致性模型,以维护副本数据一致性:强一致性 (sync) 确保写操作仅在复制到所有从节点后才完成;最终一致性 (async) 则在主节点上写操作后认为已完成,牺牲一致性换取性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

756

6

mysql和redis怎么保证双写一致性
mysql和redis怎么保证双写一致性

确保 mysql 和 redis 双写一致性的技术包括:1、事务性更新:同时更新 mysql 和 redis,保证一致性;2、主从复制:mysql 主服务器更改同步到 redis 从服务器;3、基于事件的更新:mysql 记录更改并发送到 redis等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

7542

6

redis缓存一般存些什么数据
redis缓存一般存些什么数据

redis缓存中存储的数据类型包括:字符串、哈希、列表、集合、有序集合、位图、地理空间数据和hyperloglog。这些数据类型适用于存储各种数据,从简单信息到复杂对象和地理位置。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

1160

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
phpEnv手册
phpEnv手册

共0课时 | 0人学习