7. 并发:原子、Lua、库存、限流
目标:讲清 Redis 侧「并发安全」靠什么——单线程命令、Lua 脚本、正确的锁与限流,而不是在应用里瞎加锁。
原子操作
单条 Redis 命令在服务端执行期间不会被其它命令打断(主线程串行执行命令)。
常用:
INCR/DECR/INCRBY:计数、库存粗扣SET key value NX PX:加锁SETNX已不推荐单独用(易忘过期)
边界: 多条命令默认不原子。要组合逻辑 → Lua 或 Redisson 等封装。
Lua
Redis 执行 Lua 期间,其它命令插不进来,适合:
- 校验 + 删除锁(防误删)
- 扣库存:读余量 → 判断 → 扣减
- 限流窗口内计数 + 过期
原则:
- 脚本要短、确定性、避免大循环
- 尽量用
EVALSHA减网络传脚本开销 - 不要在 Lua 里做外部 IO
库存扣减
简单版(面试常答):
text
Lua / 原子:
若 stock <= 0 → 失败
否则 DECR → 成功注意:
- Redis 扣成功 ≠ 订单落库成功 → 要有对账 / 回滚库存 / 预扣+确认
- 超卖防护在 Redis;资金与订单权威仍在 DB 事务
优化: 热点 SKU 分桶库存(sku:1001:bucket:0..N)降低单 Key 竞争;最终汇总。
限流
常见:
| 方式 | 思路 | 场景 |
|---|---|---|
| 固定窗口计数 | INCR + 首次数 EXPIRE | 简单接口限流 |
| 滑动窗口 | ZSet 时间戳成员 | 更平滑 |
| 令牌桶 / 漏桶 | 应用或网关实现,Redis 存状态 | 网关层更常见 |
口述:
接口限流我用 Redis 做分布式计数,Key 带用户或 IP + 接口 + 窗口;超阈值直接拒绝。要平滑再用滑动窗口;网关层限流和业务限流分层。
核心优化
- 多步逻辑 → Lua 或成熟组件,忌客户端「先读后写」无锁
- 库存与订单状态机分开设计,避免「只信 Redis」
- 限流 Key 必须带维度与窗口,并设过期防泄漏
- 压测热 Key 限流/库存,必要时分片