下游 TiDB 表结构有更多列的迁移场景

本文介绍如何在下游 TiDB 表结构比上游存在更多列的情况下,使用 DM 对表进行迁移。

数据源表

本文档示例所用的数据源实例如下所示:

Schema Tables
user information, log
store store_bj, store_tj
log messages

迁移要求

在 TiDB 中定制创建表 log.messages,其表结构包含数据源中 log.messages 表的所有列,且比数据源的表结构有更多的列。在此需求下,将数据源表 log.messages 迁移到 TiDB 集群的表 log.messages

注意:

  • 下游 TiDB 相比于数据源多出的列必须指定默认值或允许为 NULL
  • 对于已经通过 DM 在正常迁移的表,可直接在下游 TiDB 中新增指定了默认值或允许为 NULL 的列而不会影响 DM 正常的数据迁移。

数据迁移操作

下面介绍满足以上迁移要求的具体操作步骤。

在下游 TiDB 中手动创建表结构

假设在开始进行数据迁移时,数据源表结构为:

  1. CREATE TABLE `messages` (
  2. `id` int(11) NOT NULL,
  3. `message` varchar(255) DEFAULT NULL,
  4. PRIMARY KEY (`id`)
  5. )

手动在下游 TiDB 中创建表结构,比数据源多出 annotation 列:

  1. CREATE TABLE `messages` (
  2. `id` int(11) NOT NULL,
  3. `message` varchar(255) DEFAULT NULL,
  4. `annotation` varchar(255) DEFAULT NULL,
  5. PRIMARY KEY (`id`)
  6. )

创建数据迁移任务

  1. 创建任务配置文件 task.yaml,配置增量同步模式,以及每个数据源的同步起点。完整的任务配置文件示例如下:

    1. name: task-test # 任务名称,需要全局唯一
    2. task-mode: all # 进行全量数据迁移 + 增量数据迁移
    3. ## 配置下游 TiDB 数据库实例访问信息
    4. target-database: # 下游数据库实例配置
    5. host: "127.0.0.1"
    6. port: 4000
    7. user: "root"
    8. 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: ["log"] # 迁移哪些库
    13. ## 配置数据源
    14. mysql-instances:
    15. - source-id: "mysql-01" # 数据源对象 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.000001"
    20. binlog-pos: 2022
    21. binlog-gtid: "09bec856-ba95-11ea-850a-58f2b4af5188:1-9"
  2. 使用 start-task 命令创建同步任务:

    1. tiup dmctl --master-addr <master-addr> start-task task.yaml
    1. {
    2. "result": true,
    3. "msg": "",
    4. "sources": [
    5. {
    6. "result": true,
    7. "msg": "",
    8. "source": "mysql-01",
    9. "worker": "127.0.0.1:8262"
    10. }
    11. ]
    12. }
  3. 使用 query-status 查看同步任务,确认无报错信息:

    1. tiup dmctl --master-addr <master-addr> query-status test
    1. {
    2. "result": true,
    3. "msg": "",
    4. "sources": [
    5. {
    6. "result": true,
    7. "msg": "",
    8. "sourceStatus": {
    9. "source": "mysql-01",
    10. "worker": "127.0.0.1:8262",
    11. "result": null,
    12. "relayStatus": null
    13. },
    14. "subTaskStatus": [
    15. {
    16. "name": "task-test",
    17. "stage": "Running",
    18. "unit": "Sync",
    19. "result": null,
    20. "unresolvedDDLLockID": "",
    21. "sync": {
    22. "totalEvents": "0",
    23. "totalTps": "0",
    24. "recentTps": "0",
    25. "masterBinlog": "(mysql-bin.000001, 2022)",
    26. "masterBinlogGtid": "09bec856-ba95-11ea-850a-58f2b4af5188:1-9",
    27. "syncerBinlog": "(mysql-bin.000001, 2022)",
    28. "syncerBinlogGtid": "",
    29. "blockingDDLs": [
    30. ],
    31. "unresolvedGroups": [
    32. ],
    33. "synced": true,
    34. "binlogType": "remote"
    35. }
    36. }
    37. ]
    38. }
    39. ]
    40. }

只迁移数据源增量数据到 TiDB ,并且下游 TiDB 表结构有更多列的场景问题处理

如果该迁移任务包含全量数据迁移,迁移任务可以正常运行;但是如果你使用其他方式进行了全量迁移,只是用 DM 进行增量数据复制,可以参考只迁移数据源增量数据到 TiDB创建数据迁移任务,同时还需手动在 DM 中设置用于解析 MySQL binlog 的表结构。

否则,创建任务后,运行 query-status 会返回类似如下数据迁移错误:

  1. "errors": [
  2. {
  3. "ErrCode": 36027,
  4. "ErrClass": "sync-unit",
  5. "ErrScope": "internal",
  6. "ErrLevel": "high",
  7. "Message": "startLocation: [position: (mysql-bin.000001, 2022), gtid-set:09bec856-ba95-11ea-850a-58f2b4af5188:1-9 ], endLocation: [position: (mysql-bin.000001, 2022), gtid-set: 09bec856-ba95-11ea-850a-58f2b4af5188:1-9]: gen insert sqls failed, schema: log, table: messages: Column count doesn't match value count: 3 (columns) vs 2 (values)",
  8. "RawCause": "",
  9. "Workaround": ""
  10. }
  11. ]

出现以上错误的原因是 DM 迁移 binlog event 时,如果 DM 内部没有维护对应于该表的表结构,则会尝试使用下游当前的表结构来解析 binlog event 并生成相应的 DML 语句。如果 binlog event 里数据的列数与下游表结构的列数不一致时,则会产生上述错误。

此时,我们可以使用 operate-schema 命令来为该表指定与 binlog event 匹配的表结构。如果你在进行分表合并的数据迁移,那么需要为每个分表按照如下步骤在 DM 中设置用于解析 MySQL binlog 的表结构。具体操作为:

  1. 为数据源中需要迁移的表 log.messages 指定表结构,表结构需要对应 DM 将要开始同步的 binlog event 的数据。将对应的 CREATE TABLE 表结构语句并保存到文件,例如将以下表结构保存到 log.messages.sql 中。

    1. CREATE TABLE `messages` (
    2. `id` int(11) NOT NULL,
    3. `message` varchar(255) DEFAULT NULL,
    4. PRIMARY KEY (`id`)
    5. )
  2. 使用 operate-schema 命令设置表结构(此时 task 应该由于上述错误而处于 Paused 状态)。

    1. tiup dmctl --master-addr <master-addr> operate-schema set -s mysql-01 task-test -d log -t message log.message.sql
  3. 使用 resume-task 命令恢复处于 Paused 状态的任务。

  4. 使用 query-status 命令确认数据迁移任务是否运行正常。