技术难题:高并发场景下的“超卖”现象(库存一致性)

目录

核心冲突

[解决方案:Redis + Lua 脚本原子化处理](#解决方案:Redis + Lua 脚本原子化处理)

实现逻辑

核心代码实现

方案优化的深度思考


如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

在秒杀或抢购场景中,最经典且最令人头疼的问题莫过于库存超卖。当大量请求同时涌入,程序如果仅仅使用"读取库存 -> 扣减库存 -> 写入数据库"的逻辑,在分布式环境下必将导致库存扣减超过预定数量。

核心冲突
  1. 数据库性能瓶颈:频繁更新数据库中的同一行记录会引发锁竞争(Row Locking),导致 TPS(每秒处理事务数)暴跌。
  2. 原子性保障 :在代码层面的 if (stock > 0) 判断在并发下存在"时间差",由于非原子操作,多个线程可能同时通过检查。

解决方案:Redis + Lua 脚本原子化处理

为了解决上述问题,我们需要将库存扣减的判断与操作封装为一个原子性指令。利用 Redis 单线程执行的特性,配合 Lua 脚本,可以完美解决逻辑执行过程中的中断与竞态问题。

实现逻辑
  1. 预减库存:将库存预先加载到 Redis 中。
  2. 原子指令:客户端执行 Lua 脚本,脚本内部一次性完成:检查库存是否存在、是否充足、扣减库存三个动作。
  3. 异步落库:库存扣减成功后,通过消息队列(如 Kafka/RabbitMQ)异步将结果同步回 MySQL,减轻数据库压力。
核心代码实现

-- Lua 脚本:Redis 侧执行,确保扣减原子性

-- KEYS1: 库存 Key, ARGV1: 扣减数量

local stock = tonumber(redis.call('get', KEYS1))

local num = tonumber(ARGV1)

if stock == nil then

return -1 -- 库存未初始化

end

if stock >= num then

redis.call('decrby', KEYS1, num)

return 1 -- 扣减成功

else

return 0 -- 库存不足

end

// C伪代码:在后端服务中调用 Lua 脚本

// Redis 的 eval 命令将整个脚本发送给服务端执行,全程无锁阻塞

int result = redisCommand(context, "EVAL %s 1 stock_key 1", lua_script);

if (result == 1) {

// 扣减成功,加入 MQ 队列处理后续订单逻辑

enqueue_order_task(user_id, product_id);

} else if (result == 0) {

printf("库存不足\n");

} else {

printf("系统异常\n");

}

方案优化的深度思考

  1. 为何使用 Lua 而不是 Redis 事务 (MULTI/EXEC)? Redis 事务只能保证命令的顺序执行,但无法在 MULTI 块内执行复杂的 if-else 条件判断。Lua 脚本提供了在 Redis 服务端进行逻辑判断的能力,能确保"判断-扣减"是一个闭环。
  2. 处理热点数据 :对于极高并发,如果单个 Redis Key 压力过大,可以采用分段库存 策略。将总库存拆分为 N 个 Key(如 stock_1, stock_2...),请求随机路由到其中一个 Key。当某个分段库存耗尽时,再尝试切换到其他分段。
  3. 最终一致性 :异步落库时,必须使用幂等设计。即同一订单请求在消息队列中重复消费时,利用订单号作为唯一主键,确保 MySQL 中该条记录只会生成一次,防止因网络重试带来的二次扣减。

总结: 解决技术难题的思路往往是"转移与降维"。将逻辑从数据库层降维到 Redis 的内存层,通过原子操作(Lua)消灭竞态条件,最后通过消息队列将压力分流。这就是在分布式系统中实现高性能与数据一致性平衡的标准范式。

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

相关推荐
二宝哥12 小时前
CentOS 7.9 系统下 Redis 5.0.4 单机安装与源码编译安装指南
redis·centos
ShiXZ21318 小时前
Redis docker-compose 部署指南
redis·docker·eureka
青山木21 小时前
Redis 缓存一致性全解:从 Cache Aside 到延迟双删、Canal+MQ 的进阶之路
java·数据库·redis·后端·缓存
YDS82921 小时前
大营销平台 —— 活动SKU库存扣减业务及其一致性处理
java·spring boot·redis·rabbitmq·ddd
爬也要爬着前进1 天前
redis主从搭建
数据库·redis·缓存
用户095367515832 天前
在系统的学习 redis 前的疑惑
redis·go
吴声子夜歌2 天前
Redis 3.x——集群故障转移
java·数据库·redis·集群
明豆2 天前
Redis 分布式缓存生产实战
redis·分布式·缓存
海兰2 天前
【高速缓存】RedisVL 指南:从向量搜索到 AI 应用落地
人工智能·redis
weixin_727535622 天前
双Token认证体系深度拆解:Spring Security + JWT + Redis
redis·spring·wpf