极致it SpringBoot开发双11商品服务系统
SpringBoot 开发双 11 商品服务系统:高并发场景下的完整实战复盘
本文基于真实双 11 大促场景,从架构设计、缓存策略、库存扣减、流量治理到压测调优,完整复盘一个高并发商品服务系统的落地过程。
一、商品服务:双 11 链路的第一道关卡
(关注简介学习更多)
双 11 的流量洪峰从零点准时抵达。用户打开 App 的第一件事不是下单,而是浏览商品、查看详情、确认价格和库存——这些操作全部落在商品服务上。
商品服务承担着整个电商链路中比例最高的读请求,峰值 QPS 可达日常的数十倍。它的核心职责有三:商品信息的存储与检索(基本信息、规格参数、图文详情、价格、库存)、商品状态的精准管控(上下架、审核、库存变更)、高并发场景下的稳定输出(毫秒级响应、高可用保障、数据一致性)。
因此,商品服务是双 11 系统中最先接受考验的环节,也是必须优先保障的核心服务。
二、整体架构设计
2.1 分层架构
系统采用经典的分层架构,每层针对高并发做了专门增强:
| 层级 | 技术选型 | 核心职责 |
|---|---|---|
| 接入层 | Nginx + LVS | 四层负载均衡,流量分发 |
| 网关层 | Spring Cloud Gateway | 路由转发、统一鉴权、限流 |
| 业务层 | SpringBoot 3.x | 商品查询、上下架、库存管理 |
| 缓存层 | Caffeine + Redis Cluster | 多级缓存,99%+ 命中率 |
| 存储层 | MySQL(分库分表)+ Elasticsearch | 数据持久化与复杂检索 |
| 消息层 | RocketMQ | 异步解耦,流量削峰 |
2.2 多级缓存架构
缓存是商品服务应对高并发的核心武器。系统设计了三层缓存:
L1 本地缓存(Caffeine)
驻留在每个应用节点的内存中,存放访问频次最高的热点商品。访问延迟在微秒级,是应对极端流量冲击的第一道防线。容量有限,需配置合理的淘汰策略(基于访问时间的 W-TinyLFU 算法)。
L2 分布式缓存(Redis Cluster)
按哈希槽分布在多个节点上,存取延迟在毫秒级,可支撑数十万并发连接。所有节点共享同一份数据,一致性更容易保证。
L3 数据库(MySQL)
前两层全部失效时的兜底方案。通过分库分表和合理索引设计,确保即使缓存完全失效,数据库也能在可接受时间内返回结果。
2.3 数据存储方案
商品数据按商品 ID 进行分库分表,采用 16 个数据库、每库 64 张表的拆分方案。分片键选择商品 ID 哈希取模,保证数据分布均匀。Elasticsearch 作为辅助索引,承担复杂条件筛选和全文搜索。
三、核心功能实战要点
3.1 商品详情查询:性能优化的主战场
详情查询是所有接口中调用频率最高的。典型流程:
从本地缓存获取,命中则直接返回
未命中则查询 Redis,命中后回填本地缓存
Redis 也未命中时查询数据库,依次回填 Redis 和本地缓存
三个关键问题及解决方案:
| 问题 | 描述 | 解决方案 |
|---|---|---|
| 缓存穿透 | 查询不存在的商品 ID,请求直达 DB | 布隆过滤器预先拦截非法 ID |
| 缓存击穿 | 热点 Key 失效瞬间大量请求直击 DB | 互斥锁(SETNX),只允许单线程加载 |
| 缓存雪崩 | 大量 Key 集中失效 | 过期时间增加随机偏移,避免集中失效 |
3.2 库存扣减的原子性保障
超卖是电商绝对不能容忍的事故。系统采用 Redis Lua 脚本实现原子性库存扣减,将”检查库存是否充足”和”扣减库存”合并为一个原子操作,避免并发竞争。
Lua 脚本核心逻辑(伪代码):
获取当前库存值
若库存不足则返回错误
否则执行
DECR扣减返回扣减后的库存值
扣减成功后发送异步消息到 RocketMQ,后台任务将 Redis 中的库存变更最终同步到 MySQL。采用”缓存优先 + 最终一致性”方案,兼顾低延迟和数据可靠性。
3.3 商品上下架状态管理
上架操作不只是修改状态字段,需要触发连锁反应:校验库存和价格配置、激活促销活动、通知搜索引擎加入索引、通知推荐系统纳入候选池。下架操作则反向完成这些动作。
系统设计了一套完整的状态机管理商品生命周期:待审核 → 审核通过 → 待上架 → 已上架 → 已下架。每个状态之间的转换绑定对应的动作处理器,业务规则清晰,新增状态不影响现有逻辑。高并发场景下通过分布式锁防止同一商品被并发操作导致状态错乱。
3.4 缓存更新策略
缓存与数据库的一致性是经典难题。系统采用 “缓存双删 + 延迟双删” 方案:
更新数据库前先删除缓存
执行数据库更新
更新完成后再次删除缓存
同时利用 Canal 组件监听 MySQL binlog,异步触发缓存增量更新,实现最终一致性下的准实时同步。
四、流量治理与容错
4.1 限流策略
基于 Sentinel 实现精细化流量控制:
| 策略 | 说明 |
|---|---|
| QPS 限流 | 区分 VIP/普通用户、核心/普通商品 |
| 热点参数限流 | 爆款商品 ID 访问异常飙升时自动触发 |
| 系统自适应保护 | 根据 CPU/负载/RT 动态调整流量入口 |
4.2 熔断降级
当下游依赖(价格服务、库存服务)响应超时或异常比例过高时,Sentinel 自动熔断并返回降级数据:
价格 → 使用缓存中的历史价格
库存 → 显示”有货”(保守策略)
促销标签 → 降级为空
原则:宁可返回略有延迟或不完整的信息,也不能让用户看到错误页面或无限等待。
4.3 预热机制
系统设计了完善的预热机制:
缓存预热:启动时异步加载热点商品到本地缓存与 Redis
JVM 预热:通过提前发送少量请求触发 JIT 编译优化
连接池预热:初始化数据库连接池和 HTTP 连接池
流量预热:高峰前逐步增加流量,让系统平滑进入最佳状态
五、压测结果
经过多轮 JMeter 压测,优化前后的关键指标对比如下:
| 指标 | 优化前 | 优化后 |
|---|---|---|
| 单机 QPS | 1,200 | 8,000+ |
| 平均响应时间 | 180ms | 25ms |
| 缓存命中率 | 72% | 99.1% |
| DB 连接池占用 | 120(峰值) | 18(峰值) |
| 集群 P99 响应时间 | 超时 | 80ms |
10 万并发用户场景下,系统平稳运行无宕机。
六、踩坑与经验
6.1 Redis 大 Key 问题
早期将商品全部属性存为一个 Hash,部分商品 Value 超过 10MB,网络传输成为瓶颈。解决方案:拆分为核心字段与扩展字段两个 Key,按需加载。
6.2 日志洪水
压测时大量 INFO 日志导致磁盘 IO 飙高。解决方案:仅打印关键节点日志,接入 ELK 做离线分析。
6.3 缓存预热不足
上线首日未提前预热缓存,DB 压力瞬间增大。解决方案:增加启动缓存预加载 + 高峰前主动刷新热点数据。
6.4 分库分表跨节点查询
早期跨分片查询导致性能骤降。解决方案:通过 Elasticsearch 承担复杂检索,MySQL 层只做单分片查询。
七、总结与展望
SpringBoot 双 11 商品服务系统的核心方法论可以归纳为四个关键词:
| 关键词 | 核心思想 |
|---|---|
| 多级缓存 | 应对读流量的数量级放大 |
| 原子操作 | Lua 脚本保障库存数据准确性 |
| 流量治理 | Sentinel 限流熔断,极限压力下守护系统稳定 |
| 异步解耦 | RocketMQ 将非实时操作移出主链路,降低响应时间 |
后续演进方向包括:GraalVM Native Image 提升启动速度、基于 AI 流量预测的弹性伸缩策略、多级缓存一致性的自动补偿机制。
经历过双 11 流量考验的系统才有资格谈高并发。这套系统的设计方法和踩坑经验,可以复用到任何需要高并发读能力的业务场景中。
延伸资源:相关源码与 Docker Compose 部署脚本已在配套课程中开放,包含完整的 JMeter 压测用例与调优配置。
本作品采用《CC 协议》,转载必须注明作者和本文链接
关于 LearnKu
推荐文章: