标准答案

  1. 单个 Redis 命令在服务器端是原子执行的,例如 INCR 或 HSET;这只保证该命令内部不会和其他命令交错。
  2. MULTI/EXEC 把多条命令按顺序执行且中间不被其他客户端命令插入,但通常不提供像关系数据库那样的运行时回滚;命令语义错误可能仍在执行时暴露。
  3. Lua 脚本可把读、判断和写放在一次原子执行中,适合扣减、限流和安全释放锁等短逻辑;脚本必须短、确定、避免阻塞和外部调用。
  4. 这些机制不能把 Redis、数据库、消息队列和远程服务包成一个原子事务。涉及跨系统一致性仍要靠幂等、Outbox、状态机、补偿和对账。

题目解析

选择前先区分“避免 Redis 内部竞态”和“保证整个业务完成”。前者可以用 Lua;后者还要处理数据库提交失败、消息重复、锁超时和网络分区。

Lua 脚本过长会阻塞 Redis 的事件循环,反而拖慢所有请求。复杂计算应在应用或工作队列中完成,把脚本限制在少量读改写操作。

代码示例

限流或库存类操作可把读取、判断和写入压缩成短脚本,调用方仍需处理业务重试和结果解释。

Lua
local current = tonumber(redis.call('GET', KEYS[1]) or '0')
if current >= tonumber(ARGV[1]) then return 0 end
redis.call('INCR', KEYS[1])
return 1

常见误区

  • 认为 Redis 事务失败会自动回滚已经执行的全部命令。
  • 在 Lua 脚本中循环扫描大量 Key 或执行长时间计算。
  • 把 Redis 原子脚本当作数据库和消息队列之间的分布式事务。

作者信息