商城系统秒杀场景下的库存防超卖架构设计与实践

简介: 本文详述电商高并发场景下库存超卖问题的完整解决方案:从TOCTOU根因分析,到数据库行锁、Redis Lua预扣、RocketMQ异步落库+幂等保障的三阶段演进,最终基于阿里云SLB/Redis/RDS/RocketMQ/OSS构建稳定架构。5000 QPS压测零超卖,TPS达4600+,数据库CPU降至35%。

一、问题背景

电商商城系统在促销、秒杀等高并发场景下,最常见也最致命的问题就是库存超卖。用户下单时多个请求同时读到同一库存值,导致扣减后库存为负数,引发客诉和资损。

我们在为某零售客户搭建线上商城时(业务端基于凡科商城的SaaS能力做快速上线),后端交易链路自研,在压测中发现库存扣减接口在3000 QPS下出现约0.3%的超卖率。本文记录这个问题从定位到最终解决的完整工程过程,供有类似场景的同学参考。

二、超卖根因分析

先看最初的库存扣减逻辑:

-- 查询库存

SELECT stock FROM goods WHERE id = 1001;

-- 应用层判断

if (stock > 0) {

   // 扣减库存

   UPDATE goods SET stock = stock - 1 WHERE id = 1001;

}

这段代码在单线程下没问题,但在并发场景下存在经典的TOCTOU(Time of Check to Time of Use)问题:线程A和B同时读到stock=1,都通过检查,各自执行UPDATE,最终stock变成-1。

本质上,"查询-判断-扣减"三步操作不是一个原子操作,中间存在时间窗口,并发请求在这个窗口内都能通过检查。

三、方案演进过程

3.1 第一版:数据库行锁

最直觉的方案是利用数据库的行锁,把判断和扣减合并成一条SQL:

UPDATE goods SET stock = stock - 1 WHERE id = 1001 AND stock > 0;

通过判断affected_rows是否为1来决定是否扣减成功。这条SQL利用了InnoDB的行锁,保证原子性。

**优点**:实现简单,无需引入额外组件。

**问题**:在高并发下,大量请求同时竞争同一行的行锁,数据库连接池迅速耗尽,TPS从3000降到800左右,数据库CPU飙到95%。在凡科商城这类SaaS平台对接的高峰流量场景下,数据库层扛不住这个压力。

3.2 第二版:Redis预扣库存

将库存量同步到Redis,用Redis的单线程特性保证扣减原子性,核心使用Lua脚本:

-- stock_deduct.lua

local key = KEYS[1]

local stock = tonumber(redis.call('GET', key))

if stock and stock > 0 then

   redis.call('DECR', key)

   return 1  -- 扣减成功

else

   return 0  -- 库存不足

end

应用层调用:

@Service

public class StockService {

 

   @Autowired

   private RedisTemplate<String, String> redisTemplate;

 

   public boolean deductStock(Long goodsId) {

       String key = "stock:goods:" + goodsId;

       DefaultRedisScript<Long> script = new DefaultRedisScript<>();

       script.setScriptSource(new ResourceScriptSource(new ClassPathResource("stock_deduct.lua")));

       script.setResultType(Long.class);

 

       Long result = redisTemplate.execute(script, Collections.singletonList(key));

       return result != null && result == 1L;

   }

}

Redis预扣成功后,再异步发送MQ消息到数据库做最终扣减。这样请求链路变成了:`用户请求 → Redis预扣 → MQ异步落库`,Redis扛住了并发,数据库压力大幅降低。

**这套方案上线后**,3000 QPS下超卖率降为0,TPS稳定在2800+。但引入了新的问题:Redis和数据库的库存数据一致性。

3.3 第三版:Redis + 数据库最终一致性

Redis预扣和数据库实际扣减之间存在时间差,如果MQ消息丢失或消费失败,两边数据会不一致。解决方案:

1. **MQ可靠投递**:使用阿里云RocketMQ的事务消息机制,确保预扣成功后消息一定能投递出去。

2. **消费幂等**:数据库扣减操作通过订单号做幂等校验,避免消息重复消费导致多次扣减。

-- 幂等表

CREATE TABLE idempotent_record (

   id BIGINT PRIMARY KEY AUTO_INCREMENT,

   biz_id VARCHAR(64) NOT NULL COMMENT '业务唯一标识(订单号)',

   biz_type VARCHAR(32) NOT NULL COMMENT '业务类型',

   status TINYINT DEFAULT 0 COMMENT '处理状态: 0-处理中 1-成功',

   created_at DATETIME DEFAULT CURRENT_TIMESTAMP,

   UNIQUE KEY uk_biz (biz_id, biz_type)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

消费端处理逻辑:

public void consumeStockDeduct(StockDeductMessage message) {

   // 幂等校验

   IdempotentRecord record = new IdempotentRecord();

   record.setBizId(message.getOrderId());

   record.setBizType("STOCK_DEDUCT");

   try {

       idempotentRecordMapper.insert(record);

   } catch (DuplicateKeyException e) {

       // 已处理过,直接返回

       return;

   }

 

   // 执行数据库扣减

   int affected = goodsMapper.deductStock(message.getGoodsId(), message.getQuantity());

   if (affected == 0) {

       // 库存不足,触发回滚逻辑

       redisTemplate.opsForValue().increment("stock:goods:" + message.getGoodsId(), message.getQuantity());

   }

 

   // 更新幂等记录状态

   idempotentRecordMapper.updateStatus(message.getOrderId(), "STOCK_DEDUCT", 1);

}

四、阿里云架构实践

最终的生产架构基于阿里云产品搭建:

层级

组件

作用

接入层

阿里云SLB

负载均衡,将请求分发到多台ECS

应用层

ECS(多台)

部署商城后端服务,水平扩展

缓存层

阿里云Redis

库存预扣减、热点数据缓存

存储层

阿里云RDS for MySQL

商品、订单等核心数据持久化

消息层

阿里云RocketMQ

异步扣减消息、削峰填谷

对象存储

阿里云OSS

商品图片、静态资源存储

关键设计点:

1. **Redis与RDS库存初始化对齐**:每天凌晨通过定时任务从RDS同步库存到Redis,保证基础数据一致。秒杀活动开始前,单独触发一次同步。

2. **热点Key拆分**:爆款商品的库存Key访问量极大,容易造成Redis单分片热点。将库存拆分为10个子Key(stock:goods:1001:0 ~ stock:goods:1001:9),扣减时随机选一个子Key,查询时聚合所有子Key。

public boolean deductStockSplit(Long goodsId) {

   int shardCount = 10;

   int shard = ThreadLocalRandom.current().nextInt(shardCount);

   String key = "stock:goods:" + goodsId + ":" + shard;

 

   Long result = redisTemplate.execute(script, Collections.singletonList(key));

   if (result != null && result == 1L) {

       return true;

   }

   // 当前分片没库存,尝试其他分片

   for (int i = 0; i < shardCount; i++) {

       if (i == shard) continue;

       key = "stock:goods:" + goodsId + ":" + i;

       result = redisTemplate.execute(script, Collections.singletonList(key));

       if (result != null && result == 1L) {

           return true;

       }

   }

   return false;

}

3. **库存回补机制**:订单超时未支付时,通过RocketMQ的延迟消息触发库存回补,将Redis和RDS的库存同时加回去。

五、压测验证

在阿里云PTS(性能测试服务)上模拟秒杀场景:

指标

优化前

优化后

并发量

3000 QPS

5000 QPS

超卖率

0.3%

0%

平均RT

230ms

45ms

数据库CPU

95%

35%

TPS

800

4600

5000 QPS下系统稳定运行,零超卖,数据库CPU保持在35%左右,完全满足业务需求。

六、总结

商城系统的库存防超卖问题,核心思路是把"查询-判断-扣减"这个非原子操作变成原子操作。从数据库行锁到Redis Lua脚本预扣,再到MQ异步落库+幂等保障,是一个从强一致性向最终一致性演进的过程。

实践中有几个经验值得分享:

1. **不要过度设计**。如果并发量不高(几百QPS),数据库行锁方案就够了,没必要一上来就引入Redis+MQ的全套架构。

2. **幂等是底线**。只要涉及异步操作,幂等设计就不能省,用唯一索引是最简单可靠的方案。

3. **监控要对齐**。Redis库存和数据库库存要有定时比对告警,发现偏差及时修正,不能等用户投诉才发现。

我们在凡科商城SaaS前台+自研交易后端的混合架构下跑了大半年,经历过多次大促活动,库存数据始终准确。这套方案的核心组件都用了阿里云对应产品,如果你的技术栈也是阿里云,可以直接参考落地。

相关文章
|
9天前
|
存储 弹性计算 缓存
阿里云服务器租赁费用:新版租赁收费标准及活动报价参考
本文更新了2026年阿里云全系列云服务器租赁活动报价,所有特惠资源均可前往阿里云活动中心选购,整体覆盖从个人入门到企业级高性能场景的全梯度需求。其中轻量应用服务器主打极致性价比,2核2G峰值200M带宽配置每日10点、15点限时抢购价仅38元/年,2核4G配置379元/年起;高性价比的经济型e实例、通用算力型u2i实例覆盖2核4G至4核32G全档位,适配开发测试与中小型企业业务;搭载英特尔至强6处理器的第九代c9i企业级实例算力较上代提升20%,支撑高并发生产环境,不同实例规格价差清晰,用户可根据自身业务负载与预算灵活选型。
1894 119
阿里云服务器租赁费用:新版租赁收费标准及活动报价参考
|
10天前
|
人工智能 程序员 API
Codex 接入 DeepSeek-V4-Flash:还能补上识图,提供两套方案
Codex 接入 DeepSeek-V4-Flash 怎么配?本文覆盖 CLI 与桌面端,再用 qwen3-vl-flash 补识图,两套方案可直接照做
1451 13
|
16天前
|
云安全 人工智能 运维
阿里云联动百位企业安全专家,共识Agent防御最佳实践
当Agent成为新员工,你的安全边界在哪里?
1966 10
阿里云联动百位企业安全专家,共识Agent防御最佳实践
|
7天前
|
编解码 弹性计算 云计算
MiniMax-H3 视频生成模型 — 一键部署与使用指南
MiniMax-H3是MiniMax开源的33B全模态视频生成模型,支持文生视频、图生视频、参考生视频三种模式,原生输出2K/15秒带立体声音频视频,已原生适配ComfyUI,并可通过阿里云计算巢一键部署。(239字)
|
10天前
|
人工智能 JSON Shell
2026AI漫剧本地全开源方案(附各个软件模型链接),8G显卡也能流畅运行
这是一套完全本地化部署的AI漫剧生成技术链路:涵盖LLM剧本分镜生成、FLUX文生图(IP-Adapter人脸锁定)、StoryDiffusion时序连贯控制、LTX-2.3唇形同步视频生成,及ComfyUI全流程调度。零云端费用,仅耗硬件算力,单集2–4小时可产出竖屏短视频,适配抖音/B站分发。
|
8天前
|
人工智能 API 开发工具
2026 零基础本地 AI 漫剧完整实操教程(8G 笔记本显卡可用|附可直接复制命令与代码)
本方案提供完全离线、本地运行的漫剧全自动制作流程:RTX3060/4050 8G显卡即可驱动,涵盖Qwen写分镜→ComfyUI统一角色绘图→LTX2.3图生微动画→Qwen3-TTS本地配音→FFmpeg自动合成,全程无水印、免API、不限次。专为低显存优化,解决变脸、闪烁、爆内存三大痛点。(239字)
|
22天前
|
人工智能 前端开发 Linux
Codex 桌面版安装 + CC Switch 接入第三方 API 完整教程(2026 最新)
2026最新教程:手把手教你安装Codex桌面版,通过CC Switch v3.17.0一键接入Fenno等国产API(兼容OpenAI Responses格式),跳过账号登录,完整启用代码审查、多步任务与上下文感知功能。零基础友好,全程图文实操。(239字)
3413 5
|
10天前
|
编解码 人工智能 安全
2核4G/4核8G/8核16G阿里云服务器如何选择实例?经济型e、通用算力型u2i与计算型c9i选哪个?
本文介绍了阿里云2核4G、4核8G、8核16G三档主流配置下经济型e、通用算力型u2i和计算型c9i三种实例的最新活动价格与适用场景。同配置下三者价差显著,以2核4G为例,经济型e低至599.93元/年,计算型c9i则高达1742.08元/年。文章详细解析了各实例的性能定位:经济型e适合轻负载入门场景,u2i兼顾稳定算力与性价比,c9i凭借第9代至强处理器与芯片级安全能力支撑高性能业务。同时提示用户可叠加满减优惠券享受折上折,建议根据业务负载与预算综合决策。
555 113