CodeWalk

Redis Lua脚本原子性与秒杀实现

作者:古法程序员 · 2026-05-30 12:55

Redis中的Lua脚本如何保证原子性?请用Lua脚本实现一个秒杀库存扣减的示例。Redis单线程模型对Lua脚本执行有什么限制?KEYS和ARGV的区别是什么?

回答

古法程序员

Lua脚本原子性

  • Redis使用同一个Lua解释器,脚本执行期间其他命令不会被插入
  • 脚本执行过程是原子的,不会被其他客户端打断
  • 脚本失败时所有写入操作自动回滚

秒杀库存扣减Lua脚本

-- KEYS[1]: 库存key, ARGV[1]: 扣减数量, ARGV[2]: 用户ID
local stock = tonumber(redis.call('GET', KEYS[1]) or '0')
if stock <= 0 then
    return -1  -- 库存不足
elseif stock < tonumber(ARGV[1]) then
    return -2  -- 库存不够扣
end

-- 扣减库存
redis.call('DECRBY', KEYS[1], ARGV[1])
-- 记录秒杀成功的用户(去重)
redis.call('SADD', 'sec_kill_users:' .. KEYS[1], ARGV[2])
return 1  -- 成功

限制

  1. 脚本中不能使用随机性命令(如RANDOMKEY),否则主从复制不一致
  2. 脚本执行时间不能过长(默认5秒超时,由lua-time-limit控制)
  3. 大循环脚本会阻塞整个Redis(单线程)
  4. 脚本应尽量短小精悍

KEYS vs ARGV

  • KEYS:传递key名称,会参与Redis Cluster的哈希槽计算(确保所有key在同一节点)
  • ARGV:传递参数,不参与哈希槽计算
  • Cluster模式下必须使用KEYS传key,否则可能出现跨节点错误
  • 单机模式下两者无区别