Redis如何利用Lua实现秒杀资格与库存的双重校验

张开发
2026/4/15 2:11:47 15 分钟阅读

分享文章

Redis如何利用Lua实现秒杀资格与库存的双重校验
必须用Lua脚本而非客户端分步判断因GETDECR在并发下必然超卖Lua在Redis端原子执行“读-判-改”避免中间插队导致库存为负或资格校验失效。为什么必须用 Lua 而不是客户端分步判断因为秒杀场景下GET 库存再 DECR 的两步操作在并发时必然出现超卖——中间可能有其他请求插队。Lua 脚本在 Redis 服务端原子执行整个“读-判-改”过程不会被中断。常见错误现象(integer) -1 出现在库存字段里或日志里反复看到“资格已用完”但用户实际没抢到——本质是业务层校验和 Redis 操作没对齐。不要在客户端做 if inventory 0 then DECR网络延迟 多实例部署会让这个判断彻底失效脚本里别用 redis.call(GET, ...) 再手动转数字直接用 tonumber(ARGV[1]) 更安全避免字符串比较陷阱如果用 EVALSHA 预加载脚本记得先 SCRIPT LOAD否则返回 NULL 导致逻辑跳过一个能同时校验用户资格和库存的 Lua 脚本怎么写核心思路把用户资格比如是否在白名单、是否已抢过和库存扣减放在同一个脚本里用 redis.call 统一查、统一改返回值明确区分成功/失败原因。示例脚本精简版if redis.call(SISMEMBER, whitelist, KEYS[1]) 0 then return {0, not_in_whitelist}endif redis.call(SISMEMBER, seckilled, KEYS[1]) 1 then return {0, already_seckilled}endlocal stock tonumber(redis.call(GET, KEYS[2]))if stock 0 then return {0, out_of_stock}endredis.call(DECR, KEYS[2])redis.call(SADD, seckilled, KEYS[1])return {1, stock - 1}说明KEYS[1] 是用户 IDKEYS[2] 是商品库存 key返回数组第一个元素是结果码第二个是附带信息。用 SISMEMBER 查白名单比 EXISTS 字符串匹配更高效也避免误匹配资格和库存检查顺序不能颠倒先确认人有资格再动库存否则可能卡住有效用户别在脚本里用 redis.log生产环境默认关闭日志且影响性能Java 客户端调用时容易漏掉的关键点Spring Data Redis 的 execute() 方法传参稍不注意就会错位导致脚本收到空 KEYS 或乱序 ARGV。 标贝科技 标贝科技-专业AI语音服务的人工智能开放平台

更多文章