ShardingSphere 实现分库分表,数据迁移面临的核心问题是:数据库中已有几千万存量数据,想要通过 ShardingSphere 实现分库分表,需要解决存量数据迁移和增量数据接入的完整落地问题。这是生产环境中非常典型的场景,核心难点在于数据迁移过程中要保证数据一致性、尽可能减少业务停机时间。
一、整体解决方案思路
针对存量数据分库分表,核心遵循 “先规划 → 再迁移 → 后验证 → 最终切换” 的步骤,具体分为 5 个核心阶段:
- 分库分表规则设计(前提):先确定分片键、分片算法、分库分表策略,避免迁移后规则不合理导致返工;
- 空表结构初始化:按设计的规则创建分片后的空库空表;
- 存量数据迁移:将原有大表数据按规则迁移到分片表中;
- 增量数据同步 & 双写:迁移期间保证新写入的数据不丢失;
- 校验 & 业务切换:验证数据一致性后,将业务流量切到 ShardingSphere 集群。
二、具体落地步骤(以 ShardingSphere 5.x 为例)
1. 第一步:分库分表规则设计(核心前提)
先明确核心规则,否则迁移的数据会不符合分片逻辑,常见设计要点:
- 分片键选择:优先选查询频率最高、值分布均匀的字段(如用户 ID、订单 ID、时间);
- 分片算法:
- 数值型分片键:用取模算法(如 user_id % 8 分 8 表)、范围算法(如订单时间按月份分表);
- 字符串型分片键:先哈希再取模(避免分布不均);
- 分库分表粒度:几千万数据建议 “分表为主、分库为辅”(如 1 库 16 表 / 2 库 8 表),避免分库过多增加运维成本。
示例 ShardingSphere 规则配置(YAML 格式):
# 数据源配置 dataSources: ds_0: url: jdbc:mysql://127.0.0.1:3306/db_0?useSSL=false username: root password: root driverClassName: com.mysql.cj.jdbc.Driver ds_1: url: jdbc:mysql://127.0.0.1:3306/db_1?useSSL=false username: root password: root driverClassName: com.mysql.cj.jdbc.Driver # 分库分表规则 rules: - !SHARDING tables: t_order: # 原大表名 actualDataNodes: ds_${0..1}.t_order_${0..7} # 2库8表,共16分片 databaseStrategy: # 分库策略 standard: shardingColumn: user_id # 分库键 shardingAlgorithmName: db_inline # 分库算法 tableStrategy: # 分表策略 standard: shardingColumn: user_id # 分表键(和分库键一致,也可不同) shardingAlgorithmName: table_inline # 分表算法 shardingAlgorithms: db_inline: # 分库算法:user_id % 2 → 0/1库 type: INLINE props: algorithm-expression: ds_${user_id % 2} table_inline: # 分表算法:user_id % 8 → 0-7表 type: INLINE props: algorithm-expression: t_order_${user_id % 8}2. 第二步:初始化分片空表
按上述规则,在对应的数据库(db_0、db_1)中创建分片表(t_order_0 ~ t_order_7),注意:
- 分片表的结构要和原大表完全一致(字段、索引、主键等);
- 建议提前创建好分片表的索引,避免迁移后批量建索引锁表。
示例建表语句(以 t_order_0 为例):
-- 在 db_0 中执行 CREATE TABLE `t_order_0` ( `order_id` bigint NOT NULL AUTO_INCREMENT, `user_id` bigint NOT NULL, `order_amount` decimal(10,2) NOT NULL, `create_time` datetime NOT NULL, PRIMARY KEY (`order_id`), KEY `idx_user_id` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 同理创建 db_0.t_order_1~7、db_1.t_order_0~73. 第三步:存量数据迁移(核心环节)
针对几千万数据,推荐 2 种迁移方案(按业务停机要求选择):
方案 1:离线迁移(适合可接受短时间停机)
- 适用场景:业务可接受 1~2 小时停机(如凌晨低峰期);
- 工具选择:
- 简单场景:ShardingSphere 自带的
shardingsphere-scaling(数据迁移工具); - 复杂场景:DataX、Canal 或第三方工具(如阿里云 DTS、腾讯云 DTS);
- 简单场景:ShardingSphere 自带的
- 操作步骤:
- 业务停机,禁止对原大表的写入 / 更新操作;
- 使用工具将原表数据按分片规则迁移到分片表中:
- 以 DataX 为例,配置任务文件(核心是按分片键计算目标表):
json
{ "job": { "content": [ { "reader": { "name": "mysqlreader", "parameter": { "username": "root", "password": "root", "connection": [ { "querySql": ["SELECT * FROM t_order;"], "jdbcUrl": ["jdbc:mysql://127.0.0.1:3306/old_db?useSSL=false"] } ] } }, "writer": { "name": "mysqlwriter", "parameter": { "username": "root", "password": "root", "preSql": [], "connection": [ { "jdbcUrl": "jdbc:mysql://127.0.0.1:3306/db_0?useSSL=false", "table": ["t_order_0", "t_order_1", "t_order_2", "t_order_3", "t_order_4", "t_order_5", "t_order_6", "t_order_7"] }, { "jdbcUrl": "jdbc:mysql://127.0.0.1:3306/db_1?useSSL=false", "table": ["t_order_0", "t_order_1", "t_order_2", "t_order_3", "t_order_4", "t_order_5", "t_order_6", "t_order_7"] } ], "table": ["t_order"], "splitPk": "user_id", // 按分片键拆分数据 "writeMode": "insert" } } } ], "setting": { "speed": { "channel": 10 // 并发数,根据数据库性能调整 } } } }
- 以 DataX 为例,配置任务文件(核心是按分片键计算目标表):
- 迁移完成后,校验数据一致性(行数、关键字段值)。
方案 2:在线迁移(无停机,适合核心业务)
- 适用场景:业务 7×24 小时运行,无法停机;
- 核心思路:双写 + 增量同步 + 数据校验 + 最终切换;
- 操作步骤:
- 业务改造:在写入原表的同时,通过 ShardingSphere 写入分片表(双写),保证增量数据同步;
- 启动增量同步工具(如 Canal):监听原表的 binlog,将迁移期间的增量数据同步到分片表;
- 后台执行存量数据迁移(不影响业务):分批迁移原表历史数据到分片表;
- 数据校验:对比原表和分片表的全量数据,确保一致;
- 切换流量:将业务的读 / 写操作从原表切换到 ShardingSphere 集群;
- 停双写和增量同步:确认业务稳定后,停止向原表写入,关闭 Canal 同步。
4. 第四步:数据校验(必做环节)
迁移后必须验证数据一致性,避免数据丢失或错误:
- 行数校验:原表总行数 = 所有分片表行数之和;
- 抽样校验:随机抽取部分数据(如按 user_id 查询),对比原表和分片表的字段值;
- 边界值校验:校验分片键的边界值(如 user_id=0、user_id = 最大值)是否分配到正确的分片表;
- 工具推荐:ShardingSphere Scaling、DataX 自带的校验功能、自定义 SQL 脚本。
5. 第五步:业务接入 ShardingSphere
- 业务应用修改数据源配置:将 JDBC 连接从原数据库改为 ShardingSphere-Proxy 的连接地址;
- 灰度发布:先将部分业务流量切到 ShardingSphere,验证读写功能正常;
- 全量切换:确认灰度无问题后,切换所有业务流量;
- 观察期:切换后监控数据库性能、ShardingSphere 日志,及时处理异常。
三、关键注意事项
- 迁移前备份:迁移前务必全量备份原数据库,避免数据丢失;
- 分片键不可改:分片键一旦确定,后续无法轻易修改,否则会导致数据分布混乱;
- 避免跨分片操作:业务 SQL 尽量避免跨分片的 join、count (*) 等操作,如需统计可通过离线任务(如 Spark、Flink)处理;
- 性能调优:
- 迁移时控制并发数,避免压垮数据库;
- 分片表建议按分片键创建主键或索引,提升查询性能;
- 回滚方案:提前制定回滚策略(如切换回原表),避免迁移失败导致业务不可用。
总结
- 存量数据分库分表的核心是先定规则,再迁数据,最后切流量,规则设计是前提,数据一致性是核心;
- 迁移方案分离线(短停机)和在线(无停机),需根据业务可用性要求选择;
- 迁移后必须做全量数据校验,且业务接入要灰度发布,降低风险。