电商分库分表技术方案
- 一、完整架构形态(你描述的正确版本)
- 二、为什么卖家侧“也要分库分表”
- 三、CDC 同步时必须明确的三条“边界线”
- 四、卖家侧能不能“写”?——原则上不允许
- 五、那 ES 还要不要?
- 六、为什么“仅用 ES”不如“卖家库 + ES”
- 七、卖家升级 / 迁移是如何工作的?
- 八、这一套方案的本质是什么?
- 九、一句话总结(给你最终判断)
- CDC的方案和ES同步,延迟对比呢
- 一、结论先行(直接可用)
- 二、为什么 CDC → 卖家库更快、更稳
- 三、什么时候 CDC → ES 会明显“慢”
- 四、什么时候 CDC → ES 的“体验是够用的”
- 五、工程实践中的推荐组合(非常成熟)
- 六、一个非常重要但常被忽略的点:延迟的“尾部”
- 七、如果你只能选一个“准实时视图”
- 八、一句话总结(给你一个工程判断标准)
- 卖家分库分表维度
- 一、为什么要区分“大卖家 / 小卖家”
- 二、是否一定要“不同集群”?——结论
- 三、三种主流实现形态
- 四、你的“先路由到集群,再 Hash”——是否正确?
- 五、Hash 设计的关键差异
- 六、卖家升级 / 降级怎么办?
- 七、常见误区(非常重要)
- 八、一句话总结
你的总结已经非常接近成熟电商的“标准答案”了。
可以明确地说:
如果目标是“大卖家场景下的卖家侧体验 + 可持续扩展”,
那么:买家分库分表作为交易主链路,数据通过 CDC / 事件同步到卖家侧,再在卖家侧按卖家维度分库分表,是业界最稳妥的方案之一。
但这里有一个非常重要的修正点:
卖家侧的数据应当是 “卖家读模型(Read Model)”,而不是另一个“交易主库”。
下面我从完整形态、关键设计点、数据一致性边界、卖家侧是否允许写、与 ES 的关系、典型落坑点六个方面,帮你把这套方案“收口”。
一、完整架构形态(你描述的正确版本)
【交易主链路(权威)】
Buyer
↓
Order Service
↓
MySQL (Shard by buyer_id) ← 事实源(Source of Truth)
↓
CDC / Binlog / Domain Event
↓
────────────────────────────────
【卖家读模型】
↓
Seller Order DB (Shard by seller_id)
↓
Seller BFF / Seller Console
(可选)
↓
ES / OLAP(分析)
关键点:
- 只有一个“事实源”(买家分库)
- 卖家库 = 派生数据(Derived State)
- CDC 是单向的
二、为什么卖家侧“也要分库分表”
如果卖家侧不分:
- Top Seller = 单库热点
- 查询 + 聚合 + 分页全部打在一个节点
- 卖家体验会随卖家规模线性下降
因此卖家侧通常:
-
Shard Key = seller_id
-
大卖家:
- 单卖家多分片
- 或独立 DB
三、CDC 同步时必须明确的三条“边界线”
这是方案能否长期稳定的关键。
1️⃣ 一致性边界
- 买家库:强一致
- 卖家库:最终一致(秒级)
卖家侧必须接受:
- 刚下单看不到
- 刚支付状态未更新
这必须是产品级共识。
2️⃣ 数据完备性边界
卖家库 不需要 100% 交易字段,否则成本极高。
推荐原则:
- ✔ 订单 ID
- ✔ buyer_id(必要时)
- ✔ 金额、状态、时间
- ✔ 商品快照(必要字段)
- ❌ 不同步支付流水明细
- ❌ 不同步风控细节
3️⃣ 生命周期边界
卖家库更适合:
- 活跃订单
- 最近 N 个月
历史数据:
- 冷存
- OLAP
- 归档库
四、卖家侧能不能“写”?——原则上不允许
这是一个高频踩坑点。
正确做法:
-
卖家侧 只读
-
所有写操作:
- 发货
- 关闭
- 退款发起
-
全部:
- 回到 Order Service
- 命中买家分片
卖家库只负责:
- 快速查询
- 列表
- 聚合
否则你会遇到:
- 双写
- 冲突
- 回放失败
五、那 ES 还要不要?
答案是:仍然要,但角色更清晰了。
三层读模型分工
| 层 | 作用 |
|---|---|
| 卖家 DB | 准实时业务查询(列表、详情) |
| ES | 搜索 + 复杂筛选 + 聚合 |
| OLAP | 报表 / 财务 / 结算 |
ES 不替代卖家库,而是补强能力。
六、为什么“仅用 ES”不如“卖家库 + ES”
对比你之前的方案:
| 维度 | 仅 ES | 卖家库 + ES |
|---|---|---|
| 数据可靠性 | 中 | 高 |
| 大卖家分页 | 有限制 | 稳定 |
| 操作一致性 | 弱 | 可回主库 |
| 故障恢复 | 困难 | 可重放 |
七、卖家升级 / 迁移是如何工作的?
你前面关心的“卖家分层”在这里自然落地。
卖家升级流程(示意):
1. seller_tier = normal → big
2. 卖家库路由调整
3. CDC 回放到新分片
4. 校验
5. 切换完成
交易主库 完全不动。
八、这一套方案的本质是什么?
从架构角度讲,这是:
- CQRS
- Event Sourcing(弱化版)
- 单事实源 + 多派生视图
九、一句话总结(给你最终判断)
要获得大卖家场景下“稳定、低延迟、可扩展”的卖家体验,
标准解法是:
买家维度分库分表作为交易事实源 → 通过 CDC 构建卖家维度的读模型 → 卖家侧再按卖家分库分表,并辅以 ES / OLAP。
如果你愿意,下一步我可以:
- 帮你列一张 订单领域 CDC 同步字段白名单
- 或直接给你一版 卖家读模型表结构设计示例
CDC的方案和ES同步,延迟对比呢
这是一个非常关键、而且很多团队会低估的问题。
我先给你明确结论,再展开细节。
一、结论先行(直接可用)
在同等工程质量下:
CDC → 卖家库 的端到端延迟,通常低于 CDC → ES,
且抖动更小、可预测性更强。
经验量级(非极限值):
| 同步链路 | P50 延迟 | P99 延迟 | 抖动 |
|---|---|---|---|
| CDC → 卖家库(MySQL / PG) | 100–500 ms | < 1–2 s | 低 |
| CDC → ES | 300 ms–2 s | 3–10 s(高峰) | 高 |
这不是 ES “慢”,而是写入模型和系统特性不同导致的。
二、为什么 CDC → 卖家库更快、更稳
1️⃣ 写模型差异(本质原因)
关系型数据库:
- 单行 / 小批量写
- 同步 commit
- 写成功即可读(RC / RR)
ES:
- 写入 → 内存 buffer
- refresh 才可查询(默认 1s)
- merge / segment / fsync 有不可控成本
即使 CDC 事件“已经写入 ES”,
在 refresh 之前,查询侧仍然不可见。
2️⃣ CDC → 卖家库是“状态更新”
CDC 同步到卖家库,本质是:
UPSERT 一行订单快照
- 行级幂等
- 覆盖写
- 不需要历史版本
而 ES 同步通常是:
Index / Update Document
- 文档体大
- 字段多
- 分词 / mapping / analyzer 参与
3️⃣ 回压与抖动特性
卖家库:
- 主从延迟可控
- TPS 线性扩展
- 背压相对平滑
ES:
- bulk 队列满 → reject
- merge 导致突发 IO
- 节点恢复 / rebalancing 期间延迟暴涨
三、什么时候 CDC → ES 会明显“慢”
以下情况非常常见,而且一旦出现,延迟会被明显放大:
❌ 1️⃣ 高频小更新(订单状态流转)
- CREATED → PAID → SHIPPED → DONE
- 每次状态都写 ES
- refresh + merge 频繁
卖家库:一次 row update
ES:多次 document rewrite
❌ 2️⃣ 大卖家促销峰值
- 瞬时 QPS 暴涨
- bulk size 增大
- refresh 被迫延迟
延迟从秒级 → 十几秒,甚至分钟级
❌ 3️⃣ 映射复杂 / 文档过宽
- 大量 nested
- keyword + text 混用
- source 很大
写放大严重。
四、什么时候 CDC → ES 的“体验是够用的”
尽管如此,ES 仍然有合理使用场景:
✔ 卖家分析 / 统计
- GMV
- 订单趋势
- 分布分析
✔ 非关键列表
- 运营看板
- BI
✔ 延迟可被感知与容忍
- “数据每隔几秒刷新”
五、工程实践中的推荐组合(非常成熟)
推荐的数据流分层
CDC
│
┌──────────┴──────────┐
│ │
Seller Read DB Elasticsearch
(低延迟 / 稳定) (分析 / 搜索)
对外 SLA 定义
| 场景 | 数据源 | SLA |
|---|---|---|
| 卖家订单列表 | 卖家库 | < 1 s |
| 卖家订单详情 | 卖家库 | < 200 ms |
| 统计 / 报表 | ES | 秒级 |
六、一个非常重要但常被忽略的点:延迟的“尾部”
大卖家体验真正决定成败的,不是 P50,而是:
P95 / P99 延迟
在这点上:
- CDC → 卖家库:尾部收敛
- CDC → ES:尾部发散
这是大量线上系统得出的结论。
七、如果你只能选一个“准实时视图”
如果资源有限,只能选一个:
优先 CDC → 卖家库,而不是 ES
再逐步补 ES。
八、一句话总结(给你一个工程判断标准)
CDC → 卖家库是“准实时、可预测”的卖家体验保障;
CDC → ES 是“强分析能力、弱时效保证”的补充。
在大卖家场景下,前者决定体验,后者决定能力。
如果你愿意,下一步我可以:
- 帮你定义一份 卖家侧接口 SLA 与数据源映射表
- 或直接拆一版 CDC pipeline 的工程参数(batch、幂等、回压)设计清单
卖家分库分表维度
你的理解方向是对的,但需要更精确地拆解。
“按大卖家 / 小卖家分层分库”并不等同于一定要部署完全不同的物理集群,而是一个逻辑分层 + 可演进的资源隔离策略。
下面我从目标 → 典型架构 → 路由与 Hash 设计 → 演进路径 → 常见误区五个维度系统说明。
一、为什么要区分“大卖家 / 小卖家”
核心动机不是“数据量大”,而是 负载形态差异极端:
| 维度 | 大卖家 | 小卖家 |
|---|---|---|
| QPS | 极高、突发性强 | 低、稳定 |
| 数据量 | 极大 | 小 |
| 访问热点 | 强热点(单 seller) | 离散 |
| SLA | 要求高 | 相对宽松 |
| 变更频率 | 高(活动、促销) | 低 |
如果不拆:
- 大卖家会制造热点库 / 热点表
- Hash 在“卖家维度”失效
- 小卖家被大卖家拖垮(典型“邻居噪音”问题)
二、是否一定要“不同集群”?——结论
结论:不一定一开始就是不同集群,但架构上必须支持最终演进到不同集群。
存在三种成熟形态(按隔离程度递进):
三、三种主流实现形态
形态一:逻辑分层,物理不分集群(起步阶段)
┌────────────┐
Request ──► Gateway│ SellerRouter│
└─────┬──────┘
│
┌────────────────┴──────────────┐
│ │
小卖家逻辑库 大卖家逻辑库
(shared schema) (shared schema)
-
同一 DB 集群
-
逻辑上区分 seller_tier
-
典型手段:
seller_tier字段- 不同分片规则
- 不同限流、缓存策略
优点:成本低
缺点:资源仍然耦合
👉 只能作为过渡方案
形态二:同一集群,不同库(推荐的中期形态)
┌────────────┐
Request ──────►│ SellerRouter│
└─────┬──────┘
│
┌────────────┴─────────────┐
│ │
SmallSellerDBCluster BigSellerDBCluster
(多卖家混合) (少数/单卖家)
-
同一物理集群 or 同一云资源池
-
不同数据库 / 不同分片规则
-
大卖家可以:
- 一卖家多分片
- 单卖家独库
这是最常见、性价比最高的方案。
形态三:不同集群(终极形态)
┌────────────┐
Request ─────────►│ SellerRouter│
└─────┬──────┘
│
┌───────────────┴───────────────┐
│ │
SmallSeller Cluster BigSeller Cluster(s)
(高密度、低成本) (高性能、强隔离)
何时必须这么做?
- 双 11 / 黑五级别大卖家
- 单卖家 QPS > 10% 总流量
- 需要单独扩容、单独限流、单独降级
四、你的“先路由到集群,再 Hash”——是否正确?
答案:是的,这是正确顺序
路由优先于 Hash
正确的请求路径应是:
1️⃣ 识别 seller_id
2️⃣ 判断 seller_tier(大 / 小)
3️⃣ 路由到对应集群 / 库组
4️⃣ 在该范围内再做 Hash / 分片
为什么不能反过来?
❌ 错误做法:
hash(seller_id) → 某个库 → 再判断卖家大小
后果:
- 大卖家仍然打在一个 shard 上
- Hash 完全失效
- 无法迁移卖家
五、Hash 设计的关键差异
小卖家:高密度 Hash
shard = hash(seller_id) % N
- N 较大
- 每个 shard 多卖家
- 目标:均匀 + 高利用率
大卖家:定制化分片
常见模式:
模式 1:单卖家独库
seller_id = 12345 → db_big_seller_12345
模式 2:单卖家多分片(按业务主键)
order_shard = hash(order_id) % K
模式 3:冷热分离
- 热订单 / 实时数据
- 历史订单 / 归档库
六、卖家升级 / 降级怎么办?
这是设计是否成熟的分水岭。
必须满足:
- seller_tier 是配置驱动(非代码)
- 路由层无状态
- 支持 在线迁移
升级流程示例(小 → 大):
1. 标记 seller 为 migrating
2. 新写流量 → BigSeller 集群
3. 老数据异步迁移
4. 双读校验
5. 切换完成
七、常见误区(非常重要)
❌ 误区 1:一开始就全量多集群
- 运维成本爆炸
- 卖家规模不足以支撑
❌ 误区 2:只在 DB 层做
- 路由逻辑必须在 应用层 / 网关层
- DB 无法感知卖家业务语义
❌ 误区 3:认为这是“纯存储问题”
这是一个 系统级架构问题:
- 路由
- 缓存
- 限流
- 熔断
- 审计
都要跟着分层
八、一句话总结
“大卖家 / 小卖家分层分库”的本质不是分库,而是:
先做卖家分层路由,再在各自的资源池内 Hash,从而实现负载均衡与强隔离,并支持卖家生命周期演进。
如果你愿意,我可以:
- 直接给你一份 电商卖家分层路由的架构图
- 或帮你把它拆成 Gateway / BFF / 应用 / DB 各层的职责设计

浙公网安备 33010602011771号