管理 TiDB Data Migration 迁移表的表结构

    DM 执行增量迁移时,首先读取上游的 binlog,然后生成 SQL 语句执行到下游。但是,上游的 binlog 中并不记录表的完整结构信息,为了生成 SQL 语句,DM 内部维护了待迁移的表的 schema 信息,即表结构信息。

    为了一些特殊场景及处理其他可能的由于 schema 不匹配导致的迁移中断等问题,DM 提供了 命令来获取、修改、删除 DM 内部维护的表结构。

    DM 中的 schema 信息来源包括以下几部分:

    1. 执行全量数据迁移 (task-mode=all) 时,任务将经过 dump/load/sync(全量导出/全量导入/增量同步)三个阶段。dump 阶段将表结构信息随着数据一并导出,并自动在下游创建相关表。sync 阶段时以该表结构作为起始的表结构信息。
    2. sync 阶段中,处理 DDL 语句(如 ALTER TABLE)时,DM 执行该语句的同时更新内部维护的表结构信息。
    3. 如果任务是增量迁移 (task-mode=incremental),下游已经将待迁移的表创建完成,DM 会从下游数据库获取该表的结构信息(此行为随版本变化而不同)。

    增量迁移过程的 schema 信息维护较为复杂,在整个数据链路中包含以下几类可能相同或不同的表结构。

    • 上游当前时刻的表结构(记为 schema-U)。
    • 当前 DM 正在消费的 binlog event 的表结构(记为 schema-B,其对应于上游某个历史时刻的表结构)。
    • DM 内部(schema tracker 组件)当前维护的表结构(记为 schema-I)。
    • 下游 TiDB 集群中的表结构(记为 schema-D)。

    在大多数情况下,以上 4 类表结构一致。当上游执行 DDL 变更表结构后,schema-U 即会发生变更;DM 通过将该 DDL 应用于内部的 schema tracker 组件及下游 TiDB,会先后更新 schema-Ischema-D 以与 schema-U 保持一致,因而随后能正常消费 binlog 中在 DDL 之后对应表结构为 schema-B 的 binlog event。即当 DDL 被复制成功后,仍能保持 schema-Uschema-Bschema-Ischema-D 的一致。

    需要注意以下不一致的情况:

    • 当下游比上游多部分列时,schema-D 也可能会与 schema-Bschema-I 并不一致。全量数据迁移 (task-mode=all) 时 DM 会自动处理不一致的情况;而增量迁移 (task-mode=incremental) 时,由于任务首次启动,内部尚无 Schema 信息,DM 将自动读取下游表结构,即 schema-D,更新自身的 schema-I(此行为随版本变化而不同)。在此之后,如果 DM 使用 schema-I 解析 schema-B 的 binlog,将会导致 Column count doesn't match value count 错误,详情可参考:

    binlog-schema 命令可以获取、修改、删除 DM 内部维护的表结构 schema-I

    管理迁移表的表结构 - 图2注意

    binlog-schema 命令仅在 DM v6.0 及其以后版本支持,之前版本可使用 operate-schema 命令。

    1. manage or show table schema in schema tracker
    2. Usage:
    3. dmctl binlog-schema [command]
    4. Available Commands:
    5. delete delete table schema structure
    6. list show table schema structure
    7. Flags:
    8. -h, --help help for binlog-schema
    9. Global Flags:
    10. -s, --source strings MySQL Source ID.

    注意

    • 由于表结构在数据迁移过程中可能会发生变更,为获取确定性的表结构,当前 binlog-schema 命令仅能在数据迁移任务处于 Paused 状态时可用。
    • 强烈建议在修改表结构前,首先获取并备份表结构,以免误操作导致数据丢失。
    • delete:删除表结构
    • list:获取查看表结构
    • update:更新设置表结构
    • -s--source:
      • 必选
      • 指定操作将应用到的 MySQL 源

    如需获取表结构,可使用 binlog-schema list 命令:

    1. help binlog-schema list
    1. show table schema structure
    2. Usage:
    3. dmctl binlog-schema list <task-name> <database> <table> [flags]
    4. Flags:
    5. -h, --help help for list
    6. Global Flags:
    7. -s, --source strings MySQL Source ID.
    1. binlog-schema list -s mysql-replica-01 task_single db_single t1

    如需更新设置表结构,可使用 binlog-schema update 命令:

    1. help binlog-schema update
    1. update tables schema structure
    2. Usage:
    3. dmctl binlog-schema update <task-name> <database> <table> [schema-file] [flags]
    4. Flags:
    5. --flush flush the table info and checkpoint immediately (default true)
    6. --from-source use the schema from upstream database as the schema of the specified tables
    7. --from-target use the schema from downstream database as the schema of the specified tables
    8. -h, --help help for update
    9. Global Flags:
    10. -s, --source strings MySQL Source ID.

    假设要设置 db_single 任务对应于 mysql-replica-01 MySQL 源的 `db_single`.`t1` 表的表结构为如下所示:

    1. CREATE TABLE `t1` (
    2. `c1` int(11) NOT NULL,
    3. `c2` bigint(11) DEFAULT NULL,
    4. PRIMARY KEY (`c1`)
    5. ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin

    则将上述 CREATE TABLE 语句保存为文件(如 db_single.t1-schema.sql)后,执行如下命令:

    1. binlog-schema update -s mysql-replica-01 task_single db_single t1 db_single.t1-schema.sql

    如需删除表结构,可使用 binlog-schema delete 命令:

    1. help binlog-schema delete
    1. delete table schema structure
    2. Usage:
    3. dmctl binlog-schema delete <task-name> <database> <table> [flags]
    4. Flags:
    5. -h, --help help for delete
    6. Global Flags:
    7. -s, --source strings MySQL Source ID.

    管理迁移表的表结构 - 图4

    注意

    删除 DM 内部维护的表结构后,如果后续有该表的 DDL/DML 需要复制到下游,则 DM 会依次尝试从 checkpoint 表里 table_info 字段、乐观 shard DDL 协调中的元信息以及下游 TiDB 中对应的该表获取表结构。

    1. binlog-schema delete -s mysql-replica-01 task_single db_single t1
    1. {
    2. "result": true,
    3. "msg": "",
    4. "sources": [
    5. {
    6. "result": true,
    7. "msg": "",
    8. "source": "mysql-replica-01",
    9. "worker": "127.0.0.1:8262"
    10. }
    11. ]
    12. }