讲师中心 微信公众号
AI工具推荐 视频效率加速

如何编写一个能防止Redis缓存击穿的Lua脚本?

陌辰小哥_8585

陌辰小哥_8585

发布时间:2026-08-14 09:42:02

|

475人浏览过

|

来源于php中文网

原创

缓存击穿的本质是热点key过期瞬间大量请求穿透缓存直打DB,因key存在但已过期且无互斥锁保护重建逻辑;Lua脚本通过原子性执行“判断+加锁+返回状态”解决该问题。

如何编写一个能防止redis缓存击穿的lua脚本?

缓存击穿的本质是什么?

缓存击穿指的是某个热点 key 过期瞬间,大量请求同时穿透缓存直打 DB,造成数据库压力陡增。关键点在于:key 存在但已过期,且无互斥锁保护重建逻辑。Lua 脚本能解决这个问题,是因为 Redis 对单个 Lua 脚本的执行是原子的——只要脚本能覆盖「查缓存→发现过期→加锁→重建→写回」整个流程,就能避免并发重建。

GET + SETNX 组合为什么不够?

单纯用 GET 判断再用 SETNX 加锁,中间存在竞态窗口:两个客户端几乎同时 GET 到 nil,都尝试 SETNX,其中一个成功,另一个失败后仍可能直接去查 DB(没等锁释放或没重试)。Lua 脚本必须把「判断+加锁+返回状态」三步压进一次原子执行。

  • 不要在 Lua 里调用外部命令(比如 redis.call("GET", KEYS[1]) 后再用 if 分支决定是否 SETNX)——这本身不原子,因为 Lua 执行完后控制权就交还给客户端了
  • 正确做法是:用 EXISTS 或 TTL 检查 key 状态,再用 SET 带 nx 和 ex 参数一次性完成加锁
  • 锁的 value 必须唯一(比如用 client ID 或随机 UUID),否则释放时无法区分所有权

一个可用的防击穿 Lua 脚本长什么样?

这个脚本接收 KEYS[1](缓存 key)、ARGV[1](锁过期时间,单位秒)、ARGV[2](唯一锁标识)三个参数,返回三种状态:1 表示命中缓存,0 表示需重建(已成功加锁),-1 表示正在被其他客户端重建(需等待后重试):

Redis Skill - 高性能缓存管理
Redis Skill - 高性能缓存管理

Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。

下载
local key = KEYS[1]
local lockExpire = tonumber(ARGV[1])
local lockValue = ARGV[2]
<p>local cacheVal = redis.call("GET", key)
if cacheVal ~= false then
return 1
end</p><p>local ttl = redis.call("TTL", key)
if ttl == -2 then -- key 不存在
if redis.call("SET", key .. ":lock", lockValue, "NX", "EX", lockExpire) == "OK" then
return 0
else
return -1
end
elseif ttl == -1 then -- key 存在但永不过期(异常情况)
return 1
else -- key 存在但已过期(ttl > 0 表示剩余秒数,过期后 TTL 返回 -2)
return 1
end

注意:TTL 返回 -2 表示 key 不存在,-1 表示存在但无过期时间;而 key 过期后,GET 返回 false,TTL 也返回 -2。所以仅靠 GET 无法区分「从未写入」和「刚过期」,必须结合 TTL 判断。

客户端怎么配合这个脚本?

脚本只负责“决策”,不负责“重建”。客户端收到 0 就去查 DB、生成新值、写回缓存并删锁;收到 -1 就 sleep 后重试(建议用指数退避);收到 1 直接返回缓存值。容易漏掉的点:

  • 锁释放必须用 Lua 脚本校验 value 再 DEL,不能简单 DEL key:lock,否则可能误删别人持有的锁
  • SET 锁时的 EX 时间要明显大于 DB 查询+写缓存耗时,否则锁自动释放后多个客户端又会同时重建
  • 如果业务允许,更轻量的做法是用 GETSET 配合空值缓存(写入 "null" 并设较短过期),但对严格一致性场景不适用

真正难的不是写脚本,而是锁超时时间估算、重建失败后的兜底策略、以及空值缓存与真实 null 的区分——这些都得贴着业务来调。

热门AI工具

更多
DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

AionClaw
AionClaw Hot

AionClaw是一款面向办公、创作和编程任务的AI桌面智能体。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

相关专题

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

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

4289

2023.11.02

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

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

3795

2023.11.14

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

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

6872

2024.04.02

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

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

623

2024.04.07

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

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

736

2024.04.07

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

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

6482

2024.04.07

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

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

1140

2024.04.07

redis的8种数据类型有哪些
redis的8种数据类型有哪些

redis 提供 8 种数据类型:字符串(文本、数字、二进制)、哈希(键值对)、列表(有序集合)、集合(无序唯一元素)、有序集合(按分数排序)、地理空间(地理位置)、hyperloglog(估计大数据基数)和位图(位序列存储)。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1016

2024.04.07

LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

80

2026.09.30

热门下载

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

精品课程

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

共0课时 | 0人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn