2026年7月13日 · 4 分钟阅读

分库分表实战:拆分策略、在线迁移、动态扩容与分布式 ID

从容量与并发瓶颈出发,系统梳理垂直拆分、水平分片、路由键、跨分片限制、在线双写迁移、扩缩容和分布式 ID 设计。

分库分表不是数据库变慢后的第一选择。索引、SQL、表结构、归档、缓存和读写分离都应先评估;只有单机容量、写吞吐或维护窗口确实成为瓶颈,才值得承担分片复杂度。

为什么拆分

  • 单实例存储、IO、连接或写吞吐接近安全水位。
  • 单表工作集和索引过大,备份、DDL、归档越来越困难。
  • 不同业务域需要独立扩展、发布和故障隔离。

不存在通用的“超过几百万行必须分表”。是否拆分取决于行宽、索引、查询模式、硬件、SLO 和增长速度,应以压测与容量预测为依据。

垂直拆分与水平分片

垂直拆分按业务或字段拆:订单、支付、商品各自成库;宽表也可将低频大字段拆走。它改善边界和缓存效率,但跨域 Join 会变成 RPC 或离线聚合。

水平分片保持表结构相同,把不同记录放到不同节点:

策略优点风险
hash(user_id) % N数据和流量较均匀扩容时大量数据重映射
范围/时间路由和归档简单新分片热点明显
目录表路由灵活、易迁移单租户目录服务成为关键依赖
虚拟槽迁移槽而非修改业务规则需要维护槽到节点映射

路由键决定上限

路由键应让最常见查询能定位单分片,同时分布均匀且长期稳定。按 user_id 分片适合用户中心,却可能让“按订单号查询”需要额外映射;按 order_id 分片又不利于用户订单列表。

常用办法是冗余路由字段、建立全局索引表、搜索引擎或分析库承载跨分片查询。跨分片分页、排序、Join、唯一约束和事务都会更昂贵,设计阶段必须列出这些查询。

中间件怎么选

客户端模式在应用内完成路由,链路短、性能高,但升级需要所有应用发布。Proxy 模式对语言和应用透明,治理集中,但多一跳并需要独立高可用运维。当前可评估 Apache ShardingSphere 的 JDBC 与 Proxy 形态,不能沿用旧资料对多年未维护组件的结论。

在线迁移流程

可靠迁移不是简单双写,而是可校验、可回滚的状态机:

准备新分片与路由
→ 全量回填历史数据
→ CDC/binlog 同步增量
→ 按主键、数量、校验和持续对账
→ 灰度影子读新库
→ 分批切读
→ 切写并保留回退窗口
→ 停止旧链路并归档

应用双写会遇到一边成功一边失败、顺序颠倒和重试重复。更稳妥的方案通常以旧库为阶段性事实来源,通过 Outbox/CDC 幂等同步新库。回填必须按版本或更新时间比较,防止历史数据覆盖新值。

动态扩缩容

直接从 % 4 改成 % 8 会重映射大量数据。虚拟槽把逻辑路由与物理节点解耦:例如先定义 1024 个槽,扩容只迁移部分槽并更新映射。

迁移单元经历“复制—追增量—校验—切路由—观察—清旧数据”。切换期间请求可双读或由目录表指向权威位置。必须限速迁移,避免挤占线上数据库 IO。

分布式 ID

方案特点适用场景
UUID无中心、生成简单不要求趋势递增,注意索引局部性
数据库号段批量取号、趋势递增能接受号段服务和少量跳号
Snowflake 类时间戳 + 节点 + 序列,本地高吞吐需要管理节点号和时钟回拨
Redis INCR简单递增Redis 成为关键依赖,需评估持久化与切换

ID 需要全局唯一,但不一定连续。不要把分片号直接暴露成不可演进的业务规则;若编码时间或节点信息,要处理时钟回拨、隐私和容量边界。

工程检查清单

  • 有压测和增长数据证明必须拆分。
  • 80% 以上核心请求能由路由键定位单分片。
  • 跨分片查询、唯一约束和事务有明确替代方案。
  • 迁移支持幂等、限速、对账、灰度与回滚。
  • 扩容使用虚拟槽或目录映射,避免全量停机重哈希。
  • ID 服务有容量、时钟和故障演练。

面试回答要点

先说明分表解决单表维护与查询压力,分库解决单实例容量和吞吐;再讲路由键、hash/range 取舍和跨分片代价。迁移按全量、增量、对账、灰度、切换、回滚展开,最后补虚拟槽扩容和分布式 ID。

总结

分片把单机问题变成分布式数据治理问题。真正困难的不是取模,而是路由键、跨分片能力、在线迁移、对账回滚和未来扩容。没有这些闭环,分库分表只是在提前制造复杂度。

参考资料