标准答案
- 单个 Redis 命令在服务器端是原子执行的,例如 INCR 或 HSET;这只保证该命令内部不会和其他命令交错。
- MULTI/EXEC 把多条命令按顺序执行且中间不被其他客户端命令插入,但通常不提供像关系数据库那样的运行时回滚;命令语义错误可能仍在执行时暴露。
- Lua 脚本可把读、判断和写放在一次原子执行中,适合扣减、限流和安全释放锁等短逻辑;脚本必须短、确定、避免阻塞和外部调用。
- 这些机制不能把 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 原子脚本当作数据库和消息队列之间的分布式事务。