秒杀库存扣减用redis原子自增的巨坑

这是一个非常经典的**"看似可行,实则巨坑"**的方案。

因为为了防止库存回补,所以你需要保证库存不能为负数, 所以,你在代码层面的逻辑是:

  1. redis.decr(key)
  2. if (返回值 < 0) { redis.incr(key); return "失败"; }

结论是:千万不要这样写。

虽然逻辑上看起来"借了再还"最后是平的,但在生产环境(特别是高并发或不稳定网络环境)下,这会引发数据永久不一致性能雪崩

主要有以下 3 个致命缺陷:

1. 致命缺陷:网络中断或服务崩溃导致"只减不加"

这是最大的风险点。因为 DECRINCR两次独立的网络请求,它们之间没有原子性保护。

场景推演:

  1. 当前库存为 0。
  2. 线程 A 发起 DECR,Redis 执行成功,库存变为 -1。
  3. 线程 A 收到返回值 -1,准备发起 INCR 进行补偿回滚。
  4. 就在这毫秒之间,发生了意外:
    • 情况一: 线程 A 所在的服务器宕机/重启了(比如被 Kubernetes OOM Kill 了)。
    • 情况二: 网络抖动,线程 A 发出的 INCR 请求包丢了,或者 Redis 的响应包丢了导致超时异常。
  5. 结果: INCR 永远没有被执行。
  6. 后果: Redis 里的库存永久停留在 -1
    • 接着有人退款(真正的回滚),库存变成了 0。
    • 本来应该恢复成 1 个库存给别人抢,现在因为那个永久的 -1,这 1 个库存被"吞"了。
    • 这就是典型的"库存泄露"。

2. 性能缺陷:Redis 写压力翻倍(写放大)

Redis 的读性能极高,但写性能相对昂贵(涉及到 AOF 刷盘、主从同步)。

场景推演: 假设库存 0,这时候来了 10,000 个并发请求。

  • 使用 Lua 脚本:

    • 10,000 个请求 -> Redis 执行 Lua -> 判断 stock <= 0 -> 直接返回 0。
    • Redis 实际发生的写操作:0 次(因为没有实际扣减)。
    • Redis 只是做了一次内存读取和逻辑判断,速度飞快,不产生 AOF 日志。
  • 使用 DECR + INCR 补偿方案:

    • 10,000 个请求 -> 10,000 次 DECR(库存狂掉到 -10000)。
    • 10,000 个请求发现小于 0 -> 10,000 次 INCR(库存慢慢加回 0)。
    • Redis 实际发生的写操作:20,000 次!
    • 这 2 万次操作全部要写 AOF 日志,全部要同步给从节点(Slave)。
    • 后果: 在没货的时候,反而把 Redis 的磁盘 IO 和网络带宽打满了,可能直接把 Redis 搞挂。

3. 竞态与监控干扰

  • 监控报警失效: 正常运维中,我们通常会设置"库存 < 0 报警"。如果你用这种方案,库存会频繁在负数跳动,报警系统会一直响,导致你无法区分是"真的出 Bug 了"还是"正常的补偿逻辑"。
  • 并发视觉干扰: 在高并发瞬间,你通过 Redis 客户端查看库存,可能会看到 -500 这种数字,很难排查问题。

总结

Lua 脚本的本质不仅仅是逻辑判断,更是为了"原子性"和"减少无效写操作"。

特性 Lua 脚本方案 DECR + INCR 补偿方案
原子性 完全原子(要么全做,要么不做) 无原子性(两个独立步骤,中间可能断开)
故障后果 即使服务崩了,库存依然准确 服务崩了 = 库存永久变负
Redis 写压力 库存不足时,0 写操作 库存不足时,2倍 写操作(最致命)
推荐指数 ⭐⭐⭐⭐⭐ ☠️ (绝对禁止)

所以,宁愿多写几行 Lua 脚本代码,也不要为了省事用 DECR 后再 INCR,风险成本太高了。

相关推荐
bcbnb4 小时前
如何解析iOS崩溃日志:从获取到符号化分析
后端
许泽宇的技术分享4 小时前
当AI学会“说人话“:Azure语音合成技术的魔法世界
后端·python·flask
用户69371750013844 小时前
4.Kotlin 流程控制:强大的 when 表达式:取代 Switch
android·后端·kotlin
用户69371750013844 小时前
5.Kotlin 流程控制:循环的艺术:for 循环与区间 (Range)
android·后端·kotlin
vx_bisheyuange4 小时前
基于SpringBoot的宠物商城网站的设计与实现
spring boot·后端·宠物
bcbnb4 小时前
全面解析网络抓包工具使用:Wireshark和TCPDUMP教程
后端
leonardee4 小时前
Spring Security安全框架原理与实战
java·后端
回家路上绕了弯4 小时前
包冲突排查指南:从发现到解决的全流程实战
分布式·后端
爱分享的鱼鱼4 小时前
部署Vue+Java Web应用到云服务器完整指南
前端·后端·全栈
麦麦麦造5 小时前
比 pip 快 100 倍!更现代的 python 包管理工具,替代 pip、venv、poetry!
后端·python