从大数据量 MySQL 迁移数据到 TiDB

通常数据量较低时,使用 DM 进行迁移较为简单,可直接完成全量+持续增量迁移工作。但当数据量较大时,DM 较低的数据导入速度 (30~50 GiB/h) 可能令整个迁移周期过长。本文所称“大数据量”通常指 TiB 级别以上。

因此,本文档介绍使用 Dumpling 和 TiDB Lightning 进行全量数据迁移,其本地导入 (local backend) 模式导入速度可达每小时 500 GiB。完成全量数据迁移后,再使用 DM 完成增量数据迁移。

前提条件

资源要求

操作系统:本文档示例使用的是若干新的、纯净版 CentOS 7 实例,你可以在本地虚拟化一台主机,或在供应商提供的平台上部署一台小型的云虚拟主机。TiDB Lightning 运行过程中,默认会占满 CPU,建议单独部署在一台主机上。如果条件不允许,你可以将 TiDB Lightning 和其他组件(比如 tikv-server)部署在同一台机器上,然后设置 region-concurrency 配置项的值为逻辑 CPU 数的 75%,以限制 TiDB Lightning 对 CPU 资源的使用。

内存和 CPU:因为 TiDB Lightning 对计算机资源消耗较高,建议分配 64 GB 以上的内存以及 32 核以上的 CPU,而且确保 CPU 核数和内存(GB)比为 1:2 以上,以获取最佳性能。

磁盘空间

  • Dumpling 需要能够储存整个数据源的存储空间,即可以容纳要导出的所有上游表的空间。计算方式参考下游数据库所需空间
  • TiDB Lightning 导入期间,需要临时空间来存储排序键值对,磁盘空间需要至少能存储数据源的最大单表。
  • 若全量数据量较大,可适当加长上游 binlog 保存时间,以避免增量同步时缺必要 binlog 导致重做。

说明:目前无法精确计算 Dumpling 从 MySQL 导出的数据大小,但你可以用下面 SQL 语句统计信息表的 data_length 字段估算数据量:

  1. /* 统计所有 schema 大小,单位 MiB,注意修改 ${schema_name} */
  2. SELECT table_schema,SUM(data_length)/1024/1024 AS data_length,SUM(index_length)/1024/1024 AS index_length,SUM(data_length+index_length)/1024/1024 AS SUM FROM information_schema.tables WHERE table_schema = "${schema_name}" GROUP BY table_schema;
  3. /* 统计最大单表,单位 MiB,注意修改 ${schema_name} */
  4. SELECT table_name,table_schema,SUM(data_length)/1024/1024 AS data_length,SUM(index_length)/1024/1024 AS index_length,SUM(data_length+index_length)/1024/1024 AS SUM from information_schema.tables WHERE table_schema = "${schema_name}" GROUP BY table_name,table_schema ORDER BY SUM DESC LIMIT 5;

目标 TiKV 集群的磁盘空间要求

目标 TiKV 集群必须有足够空间接收新导入的数据。除了标准硬件配置以外,目标 TiKV 集群的总存储空间必须大于数据源大小 × 副本数量 × 2。例如,集群默认使用 3 副本,那么总存储空间需为数据源大小的 6 倍以上。公式中的 2 倍可能难以理解,其依据是以下因素的估算空间占用:

  • 索引会占据额外的空间。
  • RocksDB 的空间放大效应。

第 1 步:从 MySQL 导出全量数据

  1. 运行以下命令,从 MySQL 导出全量数据:

    1. tiup dumpling -h ${ip} -P 3306 -u root -t 16 -r 200000 -F 256MiB -B my_db1 -f 'my_db1.table[12]' -o 's3://my-bucket/sql-backup?region=us-west-2'

    Dumpling 默认导出数据格式为 SQL 文件,你也可以通过设置 --filetype 指定导出文件的类型。

    以上命令行中用到的参数描述如下。要了解更多 Dumpling 参数,请参考 Dumpling 使用文档

    | 参数 | 说明 | | - | - | | -u--user | MySQL 数据库的用户 | | -p--password | MySQL 数据库的用户密码 | | -P--port | MySQL 数据库的端口 | | -h--host | MySQL 数据库的 IP 地址 | | -t--thread | 导出的线程数。增加线程数会增加 Dumpling 并发度提高导出速度,但也会加大数据库内存消耗,因此不宜设置过大,一般不超过 64 | | -o--output | 存储导出文件的目录,支持本地文件路径或外部存储 URL 格式 | | -r--row | 用于指定单个文件的最大行数,指定该参数后 Dumpling 会开启表内并发加速导出,同时减少内存使用 | | -F | 指定单个文件的最大大小,单位为 MiB。强烈建议使用 -F 参数以避免单表过大导致备份过程中断 | | -B--database | 导出指定数据库 | | -f--filter | 导出能匹配模式的表,语法可参考 table-filter|

    请确保 ${data-path} 的空间可以容纳要导出的所有上游表,计算方式参考下游数据库所需空间。强烈建议使用 -F 参数以避免单表过大导致备份过程中断。

  2. 查看在 ${data-path} 目录下的 metadata 文件,这是 Dumpling 自动生成的元信息文件,请记录其中的 binlog 位置信息,这将在第 3 步增量同步的时候使用。

    1. SHOW MASTER STATUS:
    2. Log: mysql-bin.000004
    3. Pos: 109227
    4. GTID:

第 2 步:导入全量数据到 TiDB

  1. 编写配置文件 tidb-lightning.toml

    1. [lightning]
    2. # 日志
    3. level = "info"
    4. file = "tidb-lightning.log"
    5. [tikv-importer]
    6. # "local":默认使用该模式,适用于 TB 级以上大数据量,但导入期间下游 TiDB 无法对外提供服务。
    7. # "tidb":TB 级以下数据量也可以采用`tidb`后端模式,下游 TiDB 可正常提供服务。 关于后端模式更多信息请参阅:https://docs.pingcap.com/tidb/stable/tidb-lightning-backends
    8. backend = "local"
    9. # 设置排序的键值对的临时存放地址,目标路径必须是一个空目录,目录空间须大于待导入数据集的大小。建议设为与 `data-source-dir` 不同的磁盘目录并使用闪存介质,独占 IO 会获得更好的导入性能
    10. sorted-kv-dir = "${sorted-kv-dir}"
    11. [mydumper]
    12. # 源数据目录,即第 1 步中 Dumpling 保存数据的路径。
    13. data-source-dir = "${data-path}" # 本地或 S3 路径,例如:'s3://my-bucket/sql-backup?region=us-west-2'
    14. [tidb]
    15. # 目标集群的信息
    16. host = ${host} # 例如:172.16.32.1
    17. port = ${port} # 例如:4000
    18. user = "${user_name}" # 例如:"root"
    19. password = "${password}" # 例如:"rootroot"
    20. status-port = ${status-port} # 导入过程 Lightning 需要在从 TiDB 的“状态端口”获取表结构信息,例如:10080
    21. pd-addr = "${ip}:${port}" # 集群 PD 的地址,Lightning 通过 PD 获取部分信息,例如 172.16.31.3:2379。当 backend = "local" 时 status-port 和 pd-addr 必须正确填写,否则导入将出现异常。

    关于更多 TiDB Lightning 的配置,请参考 TiDB Lightning 配置参数

  2. 运行 tidb-lightning。如果直接在命令行中启动程序,可能会因为 SIGHUP 信号而退出,建议配合 nohupscreen 等工具,如:

    若从 Amazon S3 导入,则需将有权限访问该 S3 后端存储的账号的 SecretKey 和 AccessKey 作为环境变量传入 Lightning 节点。同时还支持从 ~/.aws/credentials 读取凭证文件。

    1. export AWS_ACCESS_KEY_ID=${access_key}
    2. export AWS_SECRET_ACCESS_KEY=${secret_key}
    3. nohup tiup tidb-lightning -config tidb-lightning.toml > nohup.out 2>&1 &
  3. 导入开始后,可以采用以下任意方式查看进度:

    • 通过 grep 日志关键字 progress 查看进度,默认 5 分钟更新一次。
    • 通过监控面板查看进度,请参考 TiDB Lightning 监控
    • 通过 Web 页面查看进度,请参考 Web 界面
  4. 导入完毕后,TiDB Lightning 会自动退出。查看 tidb-lightning.log 日志末尾是否有 the whole procedure completed 信息,如果有,表示导入成功。如果没有,则表示导入遇到了问题,可根据日志中的 error 提示解决遇到的问题。

注意:

无论导入成功与否,最后一行都会显示 tidb lightning exit。它只是表示 TiDB Lightning 正常退出,不代表任务完成。

如果导入过程中遇到问题,请参见 TiDB Lightning 常见问题

第 3 步:使用 DM 持续复制增量数据到 TiDB

添加数据源

  1. 新建 source1.yaml 文件, 写入以下内容:

    1. # 唯一命名,不可重复。
    2. source-id: "mysql-01"
    3. # DM-worker 是否使用全局事务标识符 (GTID) 拉取 binlog。使用前提是上游 MySQL 已开启 GTID 模式。若上游存在主从自动切换,则必须使用 GTID 模式。
    4. enable-gtid: true
    5. from:
    6. host: "${host}" # 例如:172.16.10.81
    7. user: "root"
    8. password: "${password}" # 支持但不推荐使用明文密码,建议使用 dmctl encrypt 对明文密码进行加密后使用
    9. port: 3306
  2. 在终端中执行下面的命令,使用 tiup dmctl 将数据源配置加载到 DM 集群中:

    1. tiup dmctl --master-addr ${advertise-addr} operate-source create source1.yaml

    该命令中的参数描述如下:

    |参数 |描述| |- |-| |--master-addr|dmctl 要连接的集群的任意 DM-master 节点的 {advertise-addr},例如:172.16.10.71:8261| |operate-source create|向 DM 集群加载数据源|

添加同步任务

  1. 编辑 task.yaml,配置增量同步模式,以及每个数据源的同步起点:

    1. name: task-test # 任务名称,需要全局唯一。
    2. task-mode: incremental # 任务模式,设为 "incremental" 即只进行增量数据迁移。
    3. # 配置下游 TiDB 数据库实例访问信息
    4. target-database: # 下游数据库实例配置。
    5. host: "${host}" # 例如:127.0.0.1
    6. port: 4000
    7. user: "root"
    8. password: "${password}" # 推荐使用经过 dmctl 加密的密文。
    9. # 使用黑白名单配置需要同步的表
    10. block-allow-list: # 数据源数据库实例匹配的表的 block-allow-list 过滤规则集,如果 DM 版本早于 v2.0.0-beta.2 则使用 black-white-list。
    11. bw-rule-1: # 黑白名单配置项 ID。
    12. do-dbs: ["${db-name}"] # 迁移哪些库。
    13. # 配置数据源
    14. mysql-instances:
    15. - source-id: "mysql-01" # 数据源 ID,即 source1.yaml 中的 source-id
    16. block-allow-list: "bw-rule-1" # 引入上面黑白名单配置。
    17. # syncer-config-name: "global" # 引用下面的 syncers 增量数据配置。
    18. meta: # task-mode 为 incremental 且下游数据库的 checkpoint 不存在时 binlog 迁移开始的位置; 如果 checkpoint 存在,则以 checkpoint 为准。
    19. # binlog-name: "mysql-bin.000004" # 第 1 步中记录的日志位置,当上游存在主从切换时,必须使用 gtid。
    20. # binlog-pos: 109227
    21. binlog-gtid: "09bec856-ba95-11ea-850a-58f2b4af5188:1-9"
    22. # 【可选配置】 如果增量数据迁移需要重复迁移已经在全量数据迁移中完成迁移的数据,则需要开启 safe mode 避免增量数据迁移报错。
    23. # 该场景多见于以下情况:全量迁移的数据不属于数据源的一个一致性快照,随后从一个早于全量迁移数据之前的位置开始同步增量数据。
    24. # syncers: # sync 处理单元的运行配置参数。
    25. # global: # 配置名称。
    26. # safe-mode: true # 设置为 true,会将来自数据源的 INSERT 改写为 REPLACE,将 UPDATE 改写为 DELETE 与 REPLACE,从而保证在表结构中存在主键或唯一索引的条件下迁移数据时可以重复导入 DML。在启动或恢复增量复制任务的前 1 分钟内 TiDB DM 会自动启动 safe mode。

    以上内容为执行迁移的最小任务配置。关于任务的更多配置项,可以参考DM 任务完整配置文件介绍

    在你启动数据迁移任务之前,建议使用check-task命令检查配置是否符合 DM 的配置要求,以降低后期报错的概率。

    1. tiup dmctl --master-addr ${advertise-addr} check-task task.yaml
  2. 使用 tiup dmctl 执行以下命令启动数据迁移任务:

    1. tiup dmctl --master-addr ${advertise-addr} start-task task.yaml

    该命令中的参数描述如下:

    |参数|描述| |-|-| |--master-addr|dmctl 要连接的集群的任意 DM-master 节点的 {advertise-addr},例如:172.16.10.71:8261| |start-task|命令用于创建数据迁移任务|

    如果任务启动失败,可根据返回结果的提示进行配置变更,再执行上述命令重新启动任务。遇到问题请参考故障及处理方法以及常见问题

查看任务状态

如需了解 DM 集群中是否存在正在运行的迁移任务及任务状态等信息,可使用 tiup dmctl 执行 query-status 命令进行查询:

  1. tiup dmctl --master-addr ${advertise-addr} query-status ${task-name}

关于查询结果的详细解读,请参考查询状态

监控任务与查看日志

要查看迁移任务的历史状态以及更多的内部运行指标,可参考以下步骤。

如果使用 TiUP 部署 DM 集群时,正确部署了 Prometheus、Alertmanager 与 Grafana,则使用部署时填写的 IP 及 端口进入 Grafana,选择 DM 的 dashboard 查看 DM 相关监控项。

DM 在运行过程中,DM-worker、DM-master 及 dmctl 都会通过日志输出相关信息。各组件的日志目录如下:

  • DM-master 日志目录:通过 DM-master 进程参数 --log-file 设置。如果使用 TiUP 部署 DM,则日志目录默认位于 /dm-deploy/dm-master-8261/log/
  • DM-worker 日志目录:通过 DM-worker 进程参数 --log-file 设置。如果使用 TiUP 部署 DM,则日志目录默认位于 /dm-deploy/dm-worker-8262/log/

探索更多