Redis Lua 脚本读取多个 key 时怎么保持原子校验
库存扣减、额度占用这类逻辑,不能先在客户端 GET 两个 key,再根据结果分别 SET:两次请求之间可能已经被另一个客户端改写。更稳妥的做法是把读取、校验和修改放进一次 Redis Lua 脚本,用 EVAL 调用;脚本在 Redis 服务端原子执行。多个 key 要放在 KEYS,业务数值放在 ARGV,Redis Cluster 中还要让这些 key 落在允许的 hash slot 范围内。
- 一个脚本内的检查与写入具有原子性,其他 Redis 活动会等脚本结束后再处理。
KEYS只放真实 key 名,ARGV放数量、阈值、状态等普通参数。- 脚本应返回稳定的数字码或短结果;生产环境还要考虑脚本缓存丢失和执行时间。
官方文档:https://redis.io/docs/latest/develop/programmability/eval-intro/
把多个 key 的检查与修改收进一段脚本
先看一个“库存足够才扣减”的最小模型。库存和用户额度分别存放在两个 key 中,脚本负责读取两者,任意一项不足就返回失败,否则同时写回新值。客户端只发起一次脚本调用,不需要自己拼接检查与修改的时间窗口。
-- KEYS[1] 是库存,KEYS[2] 是用户额度;ARGV 只传本次扣减量。
local stock = tonumber(redis.call('GET', KEYS[1]) or '0')
local quota = tonumber(redis.call('GET', KEYS[2]) or '0')
local amount = tonumber(ARGV[1])
-- 输入异常和业务不足都返回稳定的数字码,便于客户端处理。
if not amount or amount
这里的原子性不是“每条 Redis 命令都更快”,而是脚本执行期间不会被其他客户端的命令插入。失败分支没有写入,成功分支的两个 SET 也不会只完成一半。脚本应保持短小,因为 Redis 需要在脚本运行期间处理完它,过长的脚本会把延迟传给所有请求。

KEYS 和 ARGV 不是形式要求
EVAL 的第二个参数是 key 数量。数量为 2 时,命令后紧跟的两个参数会进入 KEYS[1]、KEYS[2],后面的参数才进入 ARGV。不要在 Lua 里根据用户编号拼接 key,例如 'quota:' .. ARGV[1];应由客户端先算好完整 key,再作为 KEYS 传入。
# 2 表示后面的 stock 和 quota 都是 key 名,其余 1 是普通业务参数。
redis-cli EVAL "...Lua 脚本..." 2 stock:{sku-9} quota:{user-7} 1
显式声明 key 不只是代码风格。Redis 文档要求脚本只访问作为输入传入的 key,Redis Cluster 也需要据此判断脚本涉及的 key。跨 key 操作应使用相同 hash tag,例如 stock:{sku-9} 和 quota:{sku-9},让它们共享大括号内的路由片段;不要把不同业务对象强行塞进同一脚本,先确认它们确实需要同一原子边界。

返回码、脚本缓存与慢脚本边界
脚本最好返回 {1, 'ok'} 或 {0, 'stock_not_enough'} 这样的固定结构。客户端据此区分业务拒绝、参数错误和 Redis 执行错误,而不是解析一段可能变化的提示文案。
重复执行同一参数化脚本时,可先用 SCRIPT LOAD 加载,再用 EVALSHA 按摘要调用,减少重复传输脚本内容。但脚本缓存不是持久化数据,重启、故障切换或 SCRIPT FLUSH 后可能出现 NOSCRIPT;客户端应准备回退到重新加载再执行。脚本中不要访问未声明的 key,也不要把大批量扫描塞进一次调用。
常见问题
Lua 脚本执行时其他客户端会插队吗?
不会。Redis 保证脚本原子执行,其他服务活动会等待脚本运行结束,所以脚本越长,对全局延迟的影响越明显。
ARGV 可以用来传 key 名吗?
不建议。需要被脚本访问的 key 应显式放入 KEYS;ARGV 适合数量、阈值、状态和值等普通参数。
多个 key 在 Redis Cluster 中一定能一起操作吗?
不一定。它们需要满足集群脚本的路由约束,常见做法是使用相同 hash tag;先按部署模式验证 slot 规则,再决定脚本边界。
Redis ZINCRBY 计数出现浮点误差时怎么取整
- 上一篇
- Redis ZINCRBY 计数出现浮点误差时怎么取整
- 下一篇
- Go utf8.RuneStart 怎么在字节切片中找到字符边界
-
- 数据库 · Redis | 8小时前 |
- Redis ZRANGEBYSCORE 分数边界怎么写成开区间
- 440浏览 收藏
-
- 数据库 · Redis | 15小时前 |
- Redis EXPIRE 续期时为什么会把旧过期时间覆盖
- 273浏览 收藏
-
- 数据库 · Redis | 19小时前 | Redis · 消息队列 · Stream · XTRIM · maxlen Redis Stream XTRIM
- Redis Stream 裁剪后为什么还会保留部分消息
- 441浏览 收藏
-
- 数据库 · Redis | 20小时前 | Redis · 消息队列 · Stream · XREADGROUP · Redis Stream XREADGROUP
- Redis XREADGROUP 没有新消息时怎么设置阻塞时间
- 469浏览 收藏
-
- 数据库 · Redis | 21小时前 | Redis · Stream · 消费组 · Redis Stream XPENDING Pending Entries List
- Redis XPENDING 怎么查看消费组中最老的未确认消息
- 259浏览 收藏
-
- 数据库 · Redis | 1天前 |
- Redis Lua 脚本返回数组时客户端为什么出现 nil
- 448浏览 收藏
-
- 数据库 · Redis | 1天前 | Redis · 事务 · Redis Cluster · redis Redis Cluster 哈希标签 MULTI hash slot
- Redis Cluster 跨槽位事务为什么不能直接使用 MULTI
- 300浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 57次使用
-
- SuperCLUE
- SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
- 212次使用
-
- C-Eval
- 深入了解C-Eval中文评估套件,涵盖52个学科与4级难度。本文详解其功能特点、Zero-shot/Few-shot使用方法及代码示例,助您全面评测LLM中文理解与泛化能力。
- 143次使用
-
- AI Prompt Library
- 探索AI Prompt Library免费资源库,涵盖营销、写作及多场景AI提示词。兼容ChatGPT、Claude等工具,一键复制优化输出,提升工作效率。
- 75次使用
-
- Generrated
- Generrated汇集9300+张DALL·E生成图像及对应提示词,支持查看完整图集、对比DALL·E 2与3版本差异,是AI绘图新手学习Prompt设计与获取创作灵感的实用工具。
- 55次使用
-
- Go与Redis实现分布式互斥锁和红锁
- 2022-12-22 117浏览
-
- Go+Redis实现延迟队列实操
- 2023-02-23 426浏览
-
- 一文搞懂Go语言操作Redis的方法
- 2023-01-07 171浏览
-
- Golang分布式应用之Redis示例详解
- 2023-01-07 113浏览
-
- Go Redis客户端使用的两种对比
- 2022-12-30 195浏览

