当前位置: 首页 > news >正文

【面试场景题】电商订单系统分库分表方案设计

文章目录

    • 题目
    • 一、方案设计背景与核心挑战
    • 二、分库分表核心设计
      • 1. 拆分维度选择:复合分片(时间+用户ID)
        • (1)主分片维度:时间(按季度分表)
        • (2)二次分片维度:用户ID哈希(分库分表)
      • 2. 分库分表中间件选型:Sharding-JDBC
    • 三、热/冷数据分层存储与查询优化
      • 1. 热数据存储:高性能集群
      • 2. 冷数据存储:低成本归档集群
      • 3. 查询优化方案
    • 四、订单-库存强一致性保障
      • 1. 核心流程(TCC三阶段)
        • (1)Try阶段:资源预留
        • (2)Confirm阶段:确认执行
        • (3)Cancel阶段:回滚释放
      • 2. 最终一致性补偿
    • 五、无感扩容方案
      • 1. 扩容前准备
      • 2. 灰度迁移数据
      • 3. 扩容完成
    • 六、性能压测与容量规划
      • 1. 性能压测指标(大促峰值)
      • 2. 容量规划(未来3年)
    • 七、总结

题目

一个电商平台,去年订单量3亿,预计今年及后两年每年订单量10亿。帮忙设计一个分库分表方案,需要满足以下要求:

  1. 用户可查最近三个月订单,运营需要全量订单做统计报表
  2. 交易订单和库存必须保证强一致性或可补偿。
  3. 设计合理扩容方案,保障用户无感扩容。
  4. 大促时,读QPS峰值50000,写QPS峰值10000。

一、方案设计背景与核心挑战

  1. 数据规模:当前年订单量3亿,未来3年年均10亿,3年累计订单量约33亿,单表存储极限(1000万行)下需拆分330+表,需通过分库分表解决单库单表性能瓶颈。
  2. 核心需求
    • 查询场景:用户高频查询最近3个月订单(热数据),运营低频查询全量订单(冷数据);
    • 一致性要求:订单交易与库存扣减强一致或可补偿;
    • 性能目标:大促读QPS峰值50000、写QPS峰值10000;
    • 扩容要求:支持无感扩容,避免业务中断。

二、分库分表核心设计

1. 拆分维度选择:复合分片(时间+用户ID)

(1)主分片维度:时间(按季度分表)
  • 理由:用户查询集中在“最近3个月”,按时间拆分可天然隔离热/冷数据,降低热表数据量(单季度订单量约2.5亿,按用户ID二次拆分后单表数据量可控)。
  • 拆分规则
    • 表名格式:order_{年份}{季度}(如order_2024Q1order_2024Q2);
    • 热数据范围:当前季度+前2个季度(共3个月),部署在高性能存储节点;
    • 冷数据范围:3个月前的历史订单,迁移至低成本存储(如阿里云Lindorm、AWS Aurora冷存储),仅支持运营统计查询。
(2)二次分片维度:用户ID哈希(分库分表)
  • 理由:同一用户的订单需聚合查询(如“我的全部订单”),按用户ID哈希拆分可保证用户订单落在同一分表,避免跨表聚合;同时均匀分摊写压力(写QPS峰值10000需分散到多节点)。
  • 拆分规则
    • 分库数量:初期8个库(db_order_0~db_order_7),每个库承载写QPS约1250,预留扩容空间(未来可扩至16/32库);
    • 分表数量:每个库内按用户ID哈希拆分为16张表(order_{年份}{季度}_0~order_{年份}{季度}_15),单表季度数据量≈2.5亿/(8库×16表)=195万行,远低于1000万行阈值;
  • 分片公式
    • 库索引:user_id % 8(初期),未来扩容时调整为user_id % 16(通过一致性哈希平滑过渡);
    • 表索引:user_id / 8 % 16(确保同一用户在同一库内的表聚合)。

2. 分库分表中间件选型:Sharding-JDBC

  • 选型理由
    • 轻量级客户端方案,无独立中间件部署成本,避免网络转发损耗(相比MyCat减少1次网络开销,适配读QPS 50000的性能需求);
    • 支持动态分片配置(通过配置中心实时更新分片规则),满足无感扩容;
    • 内置分布式事务(TCC/XA)、读写分离、缓存等功能,可直接对接订单-库存一致性需求。
  • 核心配置
    • 读写分离:每个分库配置1主2从,读请求路由到从库(分担50000读QPS,主库仅处理写请求);
    • 分片策略:时间分片(按订单创建时间create_time)+ 用户ID哈希分片(按user_id),复合分片算法通过Sharding-JDBC自定义实现。

三、热/冷数据分层存储与查询优化

1. 热数据存储:高性能集群

  • 存储节点:采用MySQL 8.0主从架构(1主2从),主库使用SSD磁盘(写性能提升3倍),从库开启并行复制(slave_parallel_workers=8),降低主从延迟(控制在100ms内);
  • 索引优化
    • 主键:order_id(雪花算法生成,包含时间戳,便于按时间范围查询);
    • 联合索引:user_id + create_time(优化用户查询最近3个月订单的场景,避免回表);
    • 冗余索引:order_status + create_time(优化运营“按状态筛选订单”的统计需求)。

2. 冷数据存储:低成本归档集群

  • 存储节点:迁移至MySQL冷备实例或Lindorm(时序数据库),采用HDD磁盘(成本降低60%),仅保留基础查询能力;
  • 数据迁移策略
    • 定时任务:每个季度末(如3月31日)自动将上上个季度的订单数据从热库迁移至冷库;
    • 迁移方式:分批次迁移(每批次10万条),通过Sharding-JDBC的DataPipeline工具实现,避免锁表;
    • 查询路由:Sharding-JDBC拦截查询请求,若时间范围包含冷数据,自动路由到冷库查询,用户无感知。

3. 查询优化方案

  • 用户查询:仅路由到热库(最近3个月数据),通过user_id + create_time索引快速定位,响应时间控制在100ms内;
  • 运营统计
    • 实时统计:基于热库数据,通过Sharding-JDBC的SQL Federation功能实现跨库聚合(如“今日订单总量”);
    • 离线统计:冷数据+热数据通过Spark SQL定期计算(如“年度销售报表”),结果存储到ClickHouse,运营查询时直接查ClickHouse(响应时间<500ms)。

四、订单-库存强一致性保障

采用“TCC事务+最终一致性补偿”方案,确保订单创建与库存扣减的一致性:

1. 核心流程(TCC三阶段)

(1)Try阶段:资源预留
  • 订单服务:创建“待支付”状态订单(order_status=0),写入分库分表,通过Sharding-JDBC确保订单落库原子性;
  • 库存服务:预扣减库存(stock = stock - buy_num,标记lock_stock = lock_stock + buy_num),记录库存锁定日志(lock_log,包含order_idproduct_idlock_num);
  • 约束:Try阶段失败(如库存不足),直接返回用户“库存不足”,订单不落地。
(2)Confirm阶段:确认执行
  • 触发条件:用户支付成功(支付回调通知订单服务);
  • 订单服务:更新订单状态为“已支付”(order_status=1);
  • 库存服务:确认扣减库存(stock = stock - lock_numlock_stock = lock_stock - lock_num),删除库存锁定日志;
  • 保障:Confirm阶段通过幂等设计(按order_id唯一标识),避免重复执行。
(3)Cancel阶段:回滚释放
  • 触发条件:用户超时未支付(如30分钟)或支付失败;
  • 订单服务:更新订单状态为“已取消”(order_status=-1);
  • 库存服务:释放锁定库存(stock = stock + lock_numlock_stock = lock_stock - lock_num),删除库存锁定日志;
  • 保障:Cancel阶段通过定时任务补偿(每5分钟扫描“待支付”且超时的订单,触发Cancel)。

2. 最终一致性补偿

  • 定时对账:每小时对比“订单表”与“库存锁定日志表”,若存在“待支付订单”但无对应库存锁定(或反之),触发补偿逻辑;
  • 监控告警:若TCC任一阶段失败次数超过阈值(如10次/分钟),触发短信/钉钉告警,人工介入处理。

五、无感扩容方案

采用“一致性哈希+动态分片+灰度迁移”策略,实现分库分表的无感扩容(以“8库扩16库”为例):

1. 扩容前准备

  • 新增分库:部署8个新分库(db_order_8~db_order_15),与原有分库配置一致(1主2从、SSD磁盘);
  • 配置中心:在Nacos/Apollo中新增“16库分片规则”(user_id % 16),标记为“灰度状态”。

2. 灰度迁移数据

  • 双写阶段(1~2天):
    • Sharding-JDBC开启双写模式:新订单同时写入“旧库(8库)”和“新库(16库)”,读请求仍路由到旧库;
    • 定时任务:迁移旧库中“最近3个月热数据”到新库(按用户ID哈希重新分片),每批次迁移10万条,迁移后校验数据一致性(MD5比对);
  • 读切流阶段(1天):
    • 灰度路由:将10%的用户读请求路由到新库,监控响应时间、错误率(需<0.1%);
    • 全量切流:若灰度无异常,逐步将100%读请求切换到新库,旧库保留写能力(避免双写中断)。

3. 扩容完成

  • 停止双写:确认新库数据100%一致后,关闭旧库写能力,新订单仅写入16库;
  • 旧库归档:旧库中3个月前的冷数据迁移至冷存储,旧库节点保留1周后下线(应对回滚);
  • 监控保障:扩容后1周内重点监控分库QPS分布(确保16库均匀承载)、主从延迟(<100ms)。

六、性能压测与容量规划

1. 性能压测指标(大促峰值)

指标目标值压测结果
写QPS(订单创建)1000012000(达标)
读QPS(用户查单)5000065000(达标)
订单创建响应时间P99 < 200msP99=150ms(达标)
冷数据查询响应时间P99 < 1sP99=800ms(达标)

2. 容量规划(未来3年)

  • 分库数量:当前8库→1年后16库→3年后32库(按年订单量10亿,32库×32表×100万行=10.24亿,预留20%冗余);
  • 存储容量:热数据(3个月)约2.5亿行,按每行1KB计算,需250GB(8库×31GB/库,SSD磁盘);冷数据(3年)约30亿行,需300GB(HDD磁盘);
  • 服务器配置:每分库主从节点采用4核8GB(写库)、8核16GB(读库),32库共需96台服务器(主32+从64)。

七、总结

本方案通过“时间+用户ID复合分片”解决数据规模问题,“Sharding-JDBC+读写分离”满足性能需求,“TCC+补偿”保障一致性,“一致性哈希扩容”实现无感升级,最终可支撑未来3年年均10亿订单的业务增长,同时兼顾用户查询体验与运营统计需求。


文章转载自:

http://rlOBKaNB.fwywr.cn
http://MTQ7bnT7.fwywr.cn
http://bUzKvyEG.fwywr.cn
http://5uH8MHiD.fwywr.cn
http://gLNjiYKY.fwywr.cn
http://zi2LwBUT.fwywr.cn
http://LI8yrSgh.fwywr.cn
http://UkoPg4Vf.fwywr.cn
http://0q8OyIig.fwywr.cn
http://GYJX7DZQ.fwywr.cn
http://TGMyZbpL.fwywr.cn
http://FXpIiCpx.fwywr.cn
http://UttKF99o.fwywr.cn
http://PYsHE2UQ.fwywr.cn
http://H60jjDdG.fwywr.cn
http://t7GvB2Mb.fwywr.cn
http://ae8BNPQO.fwywr.cn
http://WAooIEoV.fwywr.cn
http://2JP6TmKq.fwywr.cn
http://ZeOJisxt.fwywr.cn
http://Asehcfk8.fwywr.cn
http://V39wGZ6y.fwywr.cn
http://WEcfiPw2.fwywr.cn
http://F0SLFlzC.fwywr.cn
http://k4I0fQFv.fwywr.cn
http://gFGf7NI2.fwywr.cn
http://ju5DUXnt.fwywr.cn
http://hJXgV0vI.fwywr.cn
http://XNwOnwBC.fwywr.cn
http://bwZJUSeV.fwywr.cn
http://www.dtcms.com/a/378560.html

相关文章:

  • 微服务保护全攻略:从雪崩到 Sentinel 实战
  • springcloud二-Sentinel
  • Redis 持久化与高可用实践(RDB / AOF / Sentinel / Cluster 全解析)
  • Semaphore 信号量深度解析
  • 门店网络重构:告别“打补丁”,用“云网融合”重塑数字竞争力!
  • Linux操作系统之Ubuntu
  • WSL自定义安装多个相同版本的Ubuntu子系统
  • 晶振在5G时代的角色:高精度时钟的核心支撑
  • 【JavaEE】(25) Spring 原理
  • 【科研绘图系列】R语言绘制模型预测与数据可视化
  • 音频中的PDM、PCM概念解读
  • 离线应用开发:Service Worker 与缓存
  • 1、RocketMQ概念详解
  • ZooKeeper Multi-op+乐观锁实战优化:提升分布式Worker节点状态一致性
  • 使用yolo算法对视频进行实时目标跟踪和分割
  • Tomcat日志乱码了怎么处理?
  • 新手该选哪款软件?3ds Max vs Blender深度对比
  • 剧本杀小程序系统开发:构建线上线下融合的剧本杀生态圈
  • 常用加密算法之 AES 简介及应用
  • 【SQL注入系列】JSON注入
  • 盲盒抽卡机小程序:从0到1的蜕变之路
  • 设计模式(C++)详解—工厂方法模式(1)
  • 【Proteus仿真】【51单片机】教室灯光控制器设计
  • java语言中,list<String>转成字符串,逗号分割;List<Integer>转字符串,逗号分割
  • Jenkins运维之路(Jenkins流水线改造Day01)
  • 9月11日星期四今日早报简报微语报早读
  • 阿里兵临城下,美团迎来至暗时刻?
  • 学习笔记:Javascript(5)——事件监听(用户交互)
  • window显示驱动开发—为头装载和专用监视器生成自定义合成器应用(二)
  • [K8S学习笔记] Service和Ingress的关系