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

文章目录

题目

一个电商平台,去年订单量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(订单创建) 10000 12000(达标)
读QPS(用户查单) 50000 65000(达标)
订单创建响应时间 P99 < 200ms P99=150ms(达标)
冷数据查询响应时间 P99 < 1s P99=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亿订单的业务增长,同时兼顾用户查询体验与运营统计需求。

相关推荐
程序员三藏2 小时前
2025最新的软件测试面试八股文(800+道题)
自动化测试·软件测试·python·功能测试·测试工具·面试·职场和发展
在未来等你3 小时前
Kafka面试精讲 Day 12:副本同步与数据一致性
大数据·分布式·面试·kafka·消息队列
云边云科技3 小时前
门店网络重构:告别“打补丁”,用“云网融合”重塑数字竞争力!
大数据·人工智能·安全·智能路由器·零售
渣渣盟4 小时前
Spark核心:单跳转换率计算全解析
大数据·spark·scala·apache
edisao5 小时前
[特殊字符] 从助手到引擎:基于 GPT 的战略协作系统演示
大数据·人工智能·gpt
ssshooter5 小时前
你知道怎么用 pnpm 临时给某个库打补丁吗?
前端·面试·npm
HAH-HAH5 小时前
【蓝桥杯 2024 国 Java A】粉刷匠小蓝
c++·学习·数学·算法·职场和发展·蓝桥杯·组合数学
IT毕设梦工厂5 小时前
大数据毕业设计选题推荐-基于大数据的国家医用消耗选品采集数据可视化分析系统-Hadoop-Spark-数据可视化-BigData
大数据·hadoop·信息可视化·spark·毕业设计·数据可视化·bigdata
华略创新6 小时前
利用数据分析提升管理决策水平
大数据·数据分析·crm·管理系统·软件