序言
在业务发展的早期,一个 MySQL 数据库通常就可以满足系统的需求。数据量增加了,可以优化 SQL、增加索引;读请求增加了,可以通过主从复制和读写分离分摊压力。
但是,这些方案并不能无限解决问题。
当单表数据量越来越大,单库的 CPU、内存、磁盘、IO 等资源逐渐达到瓶颈时,就需要考虑从数据库架构层面进行拆分,也就是分库分表。
分库分表本身并不复杂,真正复杂的是拆分之后的问题。
数据应该按照什么策略拆分?主键如何保证全局唯一?事务如何处理?SQL 如何路由?跨库 JOIN 和分页怎么办?一个已经运行多年的系统,又应该如何完成数据迁移和流量切换?
因此,分库分表并不是简单地将“一张表变成多张表”,而是一项完整的数据库架构改造。
本文将从分库分表的基本概念开始,介绍分库分表的拆分方式、适用场景、分片策略、ShardingSphere-JDBC 的使用,以及生产环境中的完整拆分流程。
简介
分库分表,简单来说就是当单个 MySQL 数据库或者单张数据表无法继续满足业务的数据量和性能要求时,将原本集中存储的数据按照一定规则拆分到多个数据库、多个数据表中。
这里实际上包含两个概念:分库和分表。
拆分粒度
分库
分库指的是在表数量不变的情况下对数据库进行拆分。
即一个库变多个库。
例如,原来系统只有一个 business_db,存放了以下表:
user表order表product表workflow表
随着业务发展,这个数据库中的表越来越多,同时订单、商品等核心业务产生了大量读写请求,导致整个数据库的 CPU、内存、磁盘 IO 等资源压力越来越大。
此时可以按照业务进行垂直拆分:
user_db库:user表order_db库:order表product_db库:product表workflow_db库:workflow表
原来一个数据库存放多个业务表,拆分后变为多个数据库存放不同业务表。
所以,分库主要解决的是单个数据库压力过大的问题,通过增加数据库实例,将原本集中在一个数据库上的压力分散到多个数据库。
分表
分表指的是在数据库数量不变的情況下,对数据库里面的表进行拆分,即一个表变多个表。
例如,电商系统有一张订单表order。
随着业务发展,这张表最终积累了数亿甚至几十亿条订单数据。即使 SQL 使用了合适的索引,单表数据量过大仍然可能带来索引维护、查询、更新、备份等方面的压力。
此时可以将一张 order 表按照 user_id(user_id % 100)拆成多张:
- 0 → order_00
- 1 → order_01
- …
- 99 → order_99
这样,原本一张order表 10 亿条数据,变为:
- order_00 → 约 1000 万
- order_01 → 约 1000 万
- order_02 → 约 1000 万
- …
- order_99 → 约 1000 万
这里数据库数量并没有增加,仍然可以是同一个 MySQL 实例,只是把一张非常大的表拆成了多张较小的表。
分库加分表
如果单纯分表之后,单个数据库仍然承受很大的压力,那么还可以进一步进行分库 + 分表。
例如原来order_db库的order表存放了 20 亿条数据,可以拆成:
1 | db_00 |
也就是说一个数据库的一个表数据,分散到多个数据库的多张表中,最终将数据和访问压力同时分散到多个数据库、多个数据表中。
拆分方向
当前主要的拆分方式有两种:
- 水平拆分:水平拆分就是从左往右横着切
- 垂直拆分:垂直拆分就是从上往下竖着切
水平拆分(常用)
水平拆分指的是在整个表数据结构不发生变更的情況下,我们将一张表的数据拆分成多张表。
垂直拆分
垂直拆分指的是将本来放在一张表中的字段拆分到多张表中。
比如某张表的字段太大,影响到了此表查询的性能,那么我们可以将造成此问题的字段拆分出去。
分片算法
假设现在有一张订单表字段结构如下:1
2
3
4
5
6order
├── id
├── user_id
├── shop_id
├── create_time
└── amount
现在这张表有几十亿数据,需要拆成 100 张表。
问题来了:这几十亿条数据,到底应该按照什么规则放进这 100 张表?
这就是分片算法。
例如order:
- 可以按照 user_id 分片(user_id % 100):
- order_00
- order_01
- order_02
- 可以按照 create_time 分片:
- 2026年1月 → order_202601
- 2026年2月 → order_202602
- 2026年3月 → order_202603
本质都是在回答:在不同的分片算法下,一条数据会去不同的一个分片。
那么,实际生产环境中,面对不同的业务场景,应该选择怎样的分片规则呢?
常见的分片算法
生产环境比较常见的可以归纳为:
| 分片算法 | 核心思想 | 典型分片键 | 主要特点 |
|---|---|---|---|
| Hash 切分 | 对分片键做 Hash/取模 | user_id、shop_id | 数据均匀 |
| 范围切分 | 按数据范围划分 | id、user_id | 扩容、冷热管理方便 |
| 时间切分 | 按时间范围划分 | create_time | 非常适合订单、日志、流水 |
| 映射表切分 | 建立“数据 → 分片”的映射 | 任意业务字段 | 灵活,但增加维护成本 |
| 一致性 Hash | Hash 环分片 | user_id 等 | 扩容时减少数据迁移 |
其中实际项目里最常见的还是:Hash、范围、时间。
下面分别来介绍下。
Hash 切分
例如有 100 张表:
1 | order_000 |
按照 user_id:table_index = user_id % 100,例如:
1 | user_id = 1001 |
另一个用户:
1 | user_id = 2034 |
优点
最大的优点就是:数据比较容易均匀分布,不会出现某几张表特别大。
例如:
1 | order_000 → 1000万 |
缺点
问题也比较明显:普通 Hash 取模最大的一个问题就是扩容时的数据迁移。。
如果以后从 100 张表扩容成 200 张表,原来的 user_id % 100 变成:user_id % 200,那么大量数据的路由结果都会发生变化。
例如:
1 | 1001 % 100 = 1 |
有些碰巧不变,但大量数据都会重新分布。
范围切分
范围切分就更加直观。
例如按照订单 ID:
1 | order_000:0 ~ 99999999 |
那么:
order_id=12345678→order_000order_id=123456789→order_001
优点
最大的优点是:范围非常明确。
比如我要查询WHERE id BETWEEN 100000000 AND 150000000,很容易知道数据在哪些分片。
另外,后续扩容也比较自然:
- order_000 → 0 ~ 1亿
- order_001 → 1亿 ~ 2亿
- order_002 → 2亿 ~ 3亿
- 新增:order_003 → 3亿 ~ 4亿
不需要像普通 Hash 那样重新计算所有历史数据。
缺点:热点问题
例如订单 ID 是不断递增的,比如今天:
- order_002 → 2亿 ~ 3亿
- order_003 → 3亿 ~ 4亿
那么,新订单全部进入最新的分片,于是:order_003被大量写入,成为热点,所以存在明显的写偏移。
因此,范围切分特别需要注意热点分片。
特殊范围——时间拆分
时间切分本质上是范围切分的一种特殊形式,因为时间本身就是一种范围,所以可以把它理解成:日期切分 = 按时间字段进行范围切分。
例如订单表order按照create_time进行切分,那么不同日期的数据到不同的表中:
2026-01-01 ~ 2026-01-31→order_2026012026-02-01 ~ 2026-02-28→order_2026022026-03-01 ~ 2026-03-31→order_2026032026-04-01 ~ 2026-04-30→order_202604
…
日期切分适合多数业务
由于很多业务数据天然具有明显的时间特征。
例如:
- 订单
- 支付流水
- 交易记录
- 操作日志
- GPS 轨迹
- 消息记录
- 统计数据
- 用户行为记录
例如你之前提到的环卫工人 GPS 轨迹就是非常典型的场景。
假设gps_track每天产生几千万条数据,那么完全可以每天一个轨迹表:
- gps_track_20260901
- gps_track_20260902
- gps_track_20260903
- …
当需要查询 2026-09-03 的轨迹数据时,直接去gps_track_20260903表即可。
每天产生几千万条数据。而不是:查询几十亿数据 → 单表过滤create_time索引,这样可以天然控制单表规模。
日期切分最大优势:冷热数据管理
这其实是日期切分非常重要的一个价值。
例如订单:
- 最近 3 个月 → 热数据
- 3个月 ~ 2年 → 温数据
- 2年以上 → 冷数据
那么数据库可以设计成:
1 | MySQL |
甚至可以进一步:
1 | 在线 MySQL |
比如支付宝一年前订单单独处理,就是按照数据生命周期进行冷热分离。
日期切分也有一个明显问题:热点
时间切分并不是没有问题。
假设order_20260904是今天的订单表,那么今天请求的所有新订单数据都会写到这一张表,于是就存在明显的写热点。问题:
- order_20260901 → 基本不写
- order_20260902 → 基本不写
- order_20260903 → 少量写
- order_20260904 → 大量写
所以在数据量非常大的场景下,往往不会简单地日期 → 一张表,而是进一步组合:日期 + Hash,例如:
1 | 2026-09-04 |
最终:
1 | order_20260904_00 |
这就是:时间范围 + Hash 的复合切分。
这种方案在大规模流水、日志、轨迹类数据中很有价值。
映射表切分
映射表与 Hash 不同,它不是通过:user_id % 100,直接计算,而是维护一张映射关系:
1 | user_id → database/table |
查询的时候:user_id → 查询映射关系 → 找到具体分片 → 查询对应数据库
优点
非常灵活。
例如某个大客户数据量特别大,可以单独给它一个分片:
- 普通客户 → order_00 ~ order_99
- 大客户A → order_100
- 大客户B → order_101
缺点
需要维护额外的映射关系,所以它更适合:数据分布不规则、需要高度灵活控制分片位置的场景。
一致性 Hash(了解)
普通 Hashhash(key) % N存在一个问题,当N = 10变成N = 20,则大量数据的映射都会改变。
一致性 Hash 的核心思想是:扩容时尽量只迁移少量数据,而不是重新打乱全部数据。
所以它主要解决的是:分片节点变化时,如何减少数据迁移。
不过数据库分库分表场景里,实际方案往往还要结合业务特点,不是用了“一致性 Hash”就自动解决扩容问题。
小结
| 策略 | 典型分片键 | 优点 | 缺点 | 典型场景 |
|---|---|---|---|---|
| Hash | user_id、shop_id |
数据分布均匀 | 扩容迁移复杂 | 用户、门店、订单 |
| 范围 | id |
查询范围明确,扩容自然 | 容易产生热点 | ID、金额、地区 |
| 时间 | create_time |
冷热分离、归档方便 | 当前分片容易成为热点 | 订单、流水、日志、轨迹 |
| 映射表 | 任意业务字段 | 非常灵活 | 需要维护映射关系 | 特殊客户、数据分布不均 |
| 一致性 Hash | user_id 等 |
扩容迁移量较小 | 实现复杂 | 节点动态变化场景 |
什么时候需要分库分表?
总体来说:性能出现瓶颈,并且其他优化手段无法很好的解决,比如:
- 单库出现瓶颈:
- 单表数据量较大,导致读写性能较慢
- 网络带宽不足,导致读写性能较慢
- 磁盘空间不足,导致无法正常写入数据
- CPU压力过大(busy、load过高),导致读写性能较慢
- 内存不足(缓存池命中率较低、磁盘读写 IO QPS 过高),导致读写性能较慢
分库还是分表?
根据不同维度选择合适的策略:
- 只分表:
- 单表数据量较大,单表读写性能出现瓶颈
- 经过评估单库的容量和性能可以支撑未来几年的增长
- 只分库:
- 数据库(读)写压力较大,数据库出现存储性能瓶颈
- 分库分表:
- 单表数据量较大,单表读写性能出现瓶颈
- 数据库(读)写压力较大,数据库出现存储性能瓶颈
并可结合以下指标进行评估:
- 预估数据量:建议预估三年内单表数据量大于 500W 或者单表数据文件大于 2G 就需要考虑分库分表
- 预估数据趋势:订单这类持续高速增长的数据需尽早考虑分库分表,并且要预留空间。用户这类后期增长会放缓的数据,可以延后考虑分库分表
- 预估应用场景:对于分片键变更频繁的数据,由于频繁变更分片键,需要同时做数据迁移,此时则不适合进行分库分表
- 预估业务复杂度:业务逻辑与分片逻辑绑定,会给 SQL 执行带来很多限制。所以如果对数据的查询逻辑变化非常大,通常不建议分库分表
数据增长量大、读多写少、逻辑固定适合分库分表。
新的问题与解决方案
分库分表能够解决单库单表数据量过大、并发压力过高等问题,但数据拆分之后,也会带来一系列新的问题。
在单库单表的情况下,数据库可以天然完成数据查询、排序、分页、聚合、JOIN、事务以及唯一约束等操作。而分库分表之后,数据被分散到了不同的数据库和数据表中,这些操作有些会变得更加复杂,有些甚至无法直接通过数据库完成。
例如,查询可能需要同时访问多个分片,分页和排序需要对多个分片的结果进行归并,跨库操作会产生分布式事务问题,而数据库原本提供的唯一约束也可能无法保证全局唯一,另外,如果遇到数据迁移和扩容需求,还得保证处理过程中的数据一致性。
因此,分库分表不仅要考虑“如何拆”,还要考虑“拆完之后怎么办”。下面就从实际业务场景出发,分别讨论分库分表可能遇到的问题以及对应的解决方案。
这些可能的讨论,基本都是围绕着“分、写、查、留”四字来讲的:
- 分:数据拆开了
- 怎么路由?
- 不带分片键怎么办?
- 数据倾斜怎么办?
- 写:事务拆开了,怎么处理
- 跨库事务
- 数据一致性
- 查:查询拆开了
- 分页怎么办?
- 排序怎么办?
- 聚合怎么办?
- JOIN 怎么办?
- 留:数据规模继续增长,怎么处理:
- 扩容
- 数据迁移
- 冷热分离
分:数据路由问题
- 分片键选择:具体业务具体分析,一般组合多个字段选择
- 分片路由:中间件内部处理
- 查询不带分片键:跨库/表聚合处理
- 分片空洞:根据业务情况规划好
- 热点数据倾斜:大多数情况不需要考虑,需要考虑的时候可以针对倾斜数据的服务器分配更多资源
查询不带分片键怎么办?
这个问题在实际业务里非常常见。
比如 GPS 表按照employee_id分片,那么下面的 SQL 处理没什么问题:
1 | SELECT * |
因为系统知道10086 → db_2 → table_07只查询一个分片。
但是,如果业务突然出现:
1 | SELECT * |
没有employee_id,那么系统不知道数据在哪。于是只能广播查询 / Scatter-Gather 所有库表:
1 | db0 → 查询 |
方案一:让核心查询必须携带分片键
例如业务定义为:查询某个员工轨迹,那么 API 就设计成:GET /employee/{employeeId}/tracks,而不是:GET /tracks?date=2026-09-06
方案二:非核心查询交给 ES
例如:查询 2026-09-06 所有异常轨迹、查询某区域所有员工轨迹、查询所有迟到员工、按照 GPS 区域搜索员工
这些查询天然不是按照employee_id进行的。这种情况下,与其让 MySQL:16 个分片全部查询 → 16 个结果集合并 → 排序 → 分页。
不如让 MySQL 作为交易数据库,负责“正确地存储和修改”,ES 作为查询数据库,负责“灵活地查询”。
写:数据一致性问题
- 跨库事务:从业务设计上尽量避免跨库事务。
- 分布式 ID:使用分布式唯一 ID 解决
- 全局唯一约束:交由分布式中间件生成
查:数据访问问题
- 分页
- 排序
- 聚合
- JOIN
- 全局查询
这些问题简单来说,初期基本可以交给中间件处理,最差的情况也就是多表/多库联查。
分页处理
这是分库分表非常典型的问题。
假设:
1 | SELECT * |
单库的时候 MySQL 可以处理,但是现在 db0、db1、db2、db3,每个库都可能存在符合条件的数据。
要查询:全局第 100001~100020 条订单,则不能简单地:每个库 LIMIT 100000,20,因为最终结果不是这么计算的。
实际上需要:
1 | db0 → Top 100020 |
数据量一大,代价很高。
那么有什么好的方案嘛?
方案一:禁止深分页
这是生产系统里非常常见的方式,比如最多查询前 10000 条,或者直接采用:基于游标的分页
例如:
1 | WHERE id < #{lastId} |
下一页把上一页最后一个 ID 传回来。这比 LIMIT 1000000,20 合理得多。
方案二:使用时间 + ID 做游标
例如订单:
1 | WHERE |
这样可以避免大量 OFFSET。
排序处理
例如:查询最近创建的 20 个订单,订单被分散到:db0、db1、db2、db3,每个数据库都查询:
1 | ORDER BY create_time DESC |
得到:
1 | db0 → 20条 |
然后应用程序做:多路归并,类似:
1 | db0: 100 90 80 ... |
最终得到全局 Top 20。
所以:分库分表以后,ORDER BY 不再天然意味着“全局排序”,而是:分片内部排序 → 应用层归并。
COUNT、SUM、GROUP BY 处理
例如运营人员想看:今天一共有多少订单?
单库查看非常简单:
1 | SELECT COUNT(*) |
分库之后:
1 | db0 → 100万 |
应用层:
1 | 100 + 120 + 80 + 110 = 410万 |
所以简单的:COUNT、SUM 可以:各分片计算 → 汇总。
但是:GROUP BY 会更复杂。
例如:
1 | SELECT status, COUNT(*) |
每个分片:
1 | db0: |
最后还要:
1 | SUCCESS = 100 + 200 |
更复杂的聚合怎么办?
例如:过去一年每个城市每个月的订单量
这类统计查询如果全部压在分库后的 MySQL 上,会越来越复杂。
实际工程通常会逐渐引入:
1 | MySQL |
也就是说:不要让在线交易数据库同时承担复杂分析数据库的职责。
JOIN 怎么办?
这是分库分表最麻烦的问题之一。
例如:orders、users
原来:
1 | SELECT * |
现在:
1 | orders → order_db_0 |
怎么办?如果两个表不在同一个库:MySQL无法像单库一样自然 JOIN。
方案一:按照相同分片键分片
这是最理想的方式。
例如:
1 | user |
全部按照:user_id 分片,那么 user_id = 10086 永远:
1 | user_10086 → db2 |
于是相关数据天然在同一个库。
这叫:绑定表 / 同库分片。
方案二:冗余数据
例如订单页面经常需要:订单号、用户姓名、用户手机号、商品名称、订单金额。
那么不要每次:Order → User → Product 跨库查询。
可以在订单表冗余user_name、user_phone、product_name字段,在订单创建的时候就保存下来,这样查询订单时直接查订单库,方便快捷。
方案三:应用层 JOIN
例如:订单查询出 user_id → 批量查询用户 → Java 内存中组装
可以使用:IN (id1,id2,id3…) 批量查询,而不是:N + 1 查询
留:数据运维问题
初期不用考虑,后期需要再具体讨论来解决这些问题:
- 扩容
- 数据迁移
- DDL
- 数据校验
- 监控
- 冷热数据管理
- 历史数据归档
- ES / ClickHouse / 数据仓库
扩容
实际生产怎么扩容?常见方法有几个。
方案一:预留足够多的分片
例如一开始就采用 32库 × 32 表这样比较大的设计。
虽然初期数据量只有 1 亿,但逻辑上提前设计好了,随着业务增长:逻辑分片 → 物理分片,可以逐渐扩容。
方案二:一致性哈希
此方案可以减少扩容造成的数据迁移。
但要注意:一致性哈希并不是分库分表的万能扩容方案,数据库分片更常见的还是:预分片、数据迁移、路由规则切换
方案三:数据迁移 + 双写 + 切换
这是大型系统采用的比较典型的方案:
1 | 旧集群 |
同时:旧集群 ←→ 增量数据同步 → 新集群
等新旧数据一致以后:流量→ 新集群
最后:停止旧集群
最佳实践
当业务系统运行一段时间后,发现某张表的数据量越来越大,单库的 CPU、内存、磁盘、IO 等资源逐渐达到瓶颈时,这个时候我们需要对这张表进行分库分表。
那么,直接将这张表拆了就可以了嘛?
当然不是,实际落地过程中,我们需要考虑很多维度的事情:
- 这张表从业务角度考虑,需要选择哪一个或者几个字段作为分片键?
- 分几个库几个表呢?
- 公司的服务器资源能给到多少?
- 期望读写能力提升为当前的多少倍?
- 如何平滑过渡对旧逻辑减少影响或者不影响?
- 这张表只有我们在用嘛?有其他同事在用嘛?对他们有没有影响?
因此,我们评估是否需要拆分时,需要设计一个详细的技术方案,大致按以下步骤进行:
- 流程梳理及影响评估
- 方案选型
- 拆分 SOP (重要)
- 稳定性保障
- 技术方案内部评审及优化
- 同步相关影响方:可能需要一些下游配合改造,需要提前通知他们进行拆分
除此之外,我们会根据不同的业务场景来选择不同的链路处理,比如 C 端和 B 端链路就不同,旧系统和新系统也不同,因此处理步骤上会有一些差异。
不同业务下的落地链路

完整链路:存量 + 增量 + 下游
适合大型 C 端系统、核心业务系统,既有大量历史数据,又有 Databus、数仓等下游依赖。
1.目标评估
评估:拆成几个库、几个表
目标:读写能力提升X倍、负载降低 Y%、容量要支持未来 Z 年发展。
举例:当前 20 亿,5 年后评估为 100 亿。那么需要分几个表?分几个库?
解答: 一个合理的答案,1024个表,16个库。
按 1024 个表算,拆分完单表 200 万,5 年后为 1000 万。
2.确定分片算法
根据具体的业务情况选择分片规则,一般选择哈希分片或者日期分片规则即可。
3.选择分表字段
核心思路:合理选择,尽量减少出现跨库、跨表查询
4.资源准备
向领导或者运维人员申请好对应的数据库资源。
5、代码改造
- 配置好对应的分库分表规则
- 代码改造
- 写入逻辑过渡:单写老库 → 双写 → 单写新库
- 读取逻辑过渡:读老库 → 部分读老部分读新库 → 读新库
- 灰度到全量放开:指定门店灰度、比例灰度 → 全量用户
6.增量数据同步(双写)
作用:保证增量数据在新库和老库都有
方案:
- 同步双写:同步写新库和老库
- 异步双写:写老库,监听 binlog 异步同步到新库
- 中间件同步工具:通过一定的规则将数据同步到目标库表
注意点:写新库异常不能影响原有流程
7.全(存)量数据迁移
作用:迁移老库历史数据,保证新库有全量数据
方案:
- RD 开发 Job:查询老库数据,批量循环写入新库
- 中间件同步工具:通过一定的规则将数据同步到目标库表
为了降低对数据库的压力和防止数据出错,注意:
- 控制好同步速率
- 尽量在业务低峰期执行
- 若与增量数据交叉了(尽量避免),考虑好并发问题
8.数据一致性校验、补偿
作用:确保新库数据正确,达到切读标准、检查是否存在改造遗漏点
方案:增量数据校验、全量数据校验、人工抽检
核心流程:
- 读取老库数据
- 读取新库数据
- 比较新老库数据:
- 一致则继续比较下一条数据
- 不一致则进行补偿:
- 新库存在,老库不存在:新库删除数据
- 新库不存在,老库存在:新库插入数据
- 新库存在、老库存在:比较所有字段,不一致则将新库更新为老库数据
9.灰度切读
作用:开始将流量切到新库
原则:
- 有问题及时切回老库
- 灰度放量先慢后快,每次放量观察一段时间
- 支持灵活的规则:
- 业务切:门店维度灰度
- 比例切:、百(万)分比灰度
- 全量切:一次性全部切过去
10. databus 切新库
作用:将数据库 Binlog 消费链路从老库切换到新库。
分库分表后,数据库从老库变成 n 个新库db_0、db_1、...、db_n,因此需要让 Databus 同时监听新的分库,并建立逻辑链路:新库 → 新 Databus → 下游。
迁移期间可以先启动新 Databus,使下游暂时同时接收新老库 Binlog:
1 | 老库 → 老 Databus ─┐ |
观察新链路稳定后关闭老 Databus,最终:新库 → 新 Databus → 下游
重点关注:消息重复、幂等、顺序、延迟、Binlog 位点。
核心流程:
- 启动新库 databus,此时下游会同时收到新老库的 binlog
- 观察一段时间是否正常
- 有问题及时关闭
- 没问题后关掉老库 databus
11.下游切数据源
作用:确保下游系统迁移到新库。
这里的下游系统一般是数仓,例如数仓原来逻辑为:老库 → ETL → 数仓,迁移后需要改为:新库 → ETL → 数仓。
注意确认:
- 新库数据完整;
- 同步任务能够正确访问所有分库分表;
- 数据量、字段、数据口径一致;
- 新旧数据切换期间不存在重复或遗漏。
数仓一般是每天同步一次数据,因此在指定时间内切换即可。
12.停写老库
原则:确认老库数据源全部迁移后,停写老库。
至此,分库分表流程处理结束。
后续逐步将老数据库资源逐渐下线。
B 端系统:业务切换链路
很多 B 端系统没有复杂的 Databus、数仓链路,或者下游对数据库 Binlog 没有强依赖,因此完整步骤可以简化为:
1 | 容量评估 |
核心是:数据迁移 + 业务流量切换,因此所以通常不需要第 10、11 步的Databus 切新库和下游切数据源。
由于很多系统没有 Databus,也没有复杂的数仓依赖,因此只需要保证业务系统自己从老库切到新库即可。
新系统/无需迁移历史数据:直接分片
还有一种情况更加简单:旧数据不需要迁移,或者可以舍弃旧数据,直接从新库开始写。
例如某些日志、轨迹、临时数据系统,历史数据已经过期,或者业务允许重新开始积累。
那么就不需要:
- 全量数据迁移
- 数据校验补偿
- Databus 切换
- 下游数据源切换
新库直接承接新数据,不做历史数据迁移,因此链路简单直接:
1 | 容量评估 |
三种链路对比
| 类型 | 核心链路 | 典型场景 |
|---|---|---|
| 完整迁移型 | 迁增量 → 迁存量 → 校验 → 切读 → 切 Databus → 切下游 → 停老库 | 大型 C 端、核心系统 |
| 业务切换型 | 迁增量 → 迁存量 → 校验 → 切读 → 停老库 | 普通 B 端业务系统 |
| 新库直切型 | 代码改造 → 新库直接写 → 直接 → 全量 | 无需保留历史数据的系统 |