主要特性

优质
小牛编辑
128浏览
2023-12-01

本文档介绍 DM 提供的数据迁移功能以及相关的配置选项与使用示例。

Table Routing、Block & Allow Lists、Binlog Event Filter 在匹配库表名时,有以下版本差异:

  • 对于 v1.0.5 版及后续版本,以上功能均支持通配符匹配。但注意所有版本中通配符匹配中的 * 符号 只能有一个且必须在末尾
  • 对于 v1.0.5 以前的版本,Table Routing 和 Binlog Event Filter 支持通配符,但不支持 [...][!...] 表达式。Block & Allow Lists 仅支持正则表达式。

在简单任务场景下推荐使用通配符匹配。

Table routing

Table routing 提供将上游 MySQL/MariaDB 实例的某些表迁移到下游指定表的功能。

注意:

  • 不支持对同一个表设置多个不同的路由规则。
  • Schema 的匹配规则需要单独设置,用来迁移 CREATE/DROP SCHEMA xx,例如下面参数配置
    routes:
      rule-1:
        schema-pattern: "test_*"
        table-pattern: "t_*"
        target-schema: "test"
        target-table: "t"
      rule-2:
        schema-pattern: "test_*"
        target-schema: "test"

    参数解释

    将根据 schema-pattern/table-pattern 匹配上该规则的上游 MySQL/MariaDB 实例的表迁移到下游的 target-schema/target-table

    使用示例

    下面展示了三个不同场景下的配置示例。

    分库分表合并

    假设存在分库分表场景,需要将上游两个 MySQL 实例的表 test_{1,2,3...}.t_{1,2,3...} 迁移到下游 TiDB 的一张表 test.t

    为了迁移到下游实例的表 test.t,需要创建以下 table routing 规则:

    • rule-1 用来迁移匹配上 schema-pattern: "test_*"table-pattern: "t_*" 的表的 DML/DDL 语句到下游的 test.t
    • rule-2 用来迁移匹配上 schema-pattern: "test_*" 的库的 DDL 语句,例如 CREATE/DROP SCHEMA xx

    注意:

    • 如果下游 TiDB schema: test 已经存在,并且不会被删除,则可以省略 rule-2
    • 如果下游 TiDB schema: test 不存在,只设置了 rule_1,则迁移会报错 schema test doesn't exist
      rule-1:
        schema-pattern: "test_*"
        table-pattern: "t_*"
        target-schema: "test"
        target-table: "t"
      rule-2:
        schema-pattern: "test_*"
        target-schema: "test"

    分库合并

    假设存在分库场景,将上游两个 MySQL 实例 test_{1,2,3...}.t_{1,2,3...} 迁移到下游 TiDB 的 test.t_{1,2,3...},创建一条路由规则即可:

      rule-1:
        schema-pattern: "test_*"
        target-schema: "test"

    错误的 table routing

    假设存在下面两个路由规则,test_1_bak.t_1_bak 可以匹配上 rule-1rule-2,违反 table 路由的限制而报错。

      rule-0:
        schema-pattern: "test_*"
        target-schema: "test"
      rule-1:
        schema-pattern: "test_*"
        table-pattern: "t_*"
        target-schema: "test"
        target-table: "t"
      rule-2:
        schema-pattern: "test_1_bak"
        table-pattern: "t_1_bak"
        target-schema: "test"
        target-table: "t_bak"

    Block & Allow Table Lists

    上游数据库实例表的黑白名单过滤规则,可以用来过滤或者只迁移某些 database/table 的所有操作。

    参数配置

    block-allow-list:             # 如果 DM 版本 <= v2.0.0-beta.2 则使用 black-white-list。
      rule-1:
        do-dbs: ["test*"]         # 非 ~ 字符开头,表示规则是通配符;v1.0.5 及后续版本支持通配符规则。
    ​    do-tables:
        - db-name: "test[123]"    # 匹配 test1、test2、test3。
          tbl-name: "t[1-5]"      # 匹配 t1、t2、t3、t4、t5。
        - db-name: "test"
          tbl-name: "t"
      rule-2:
        do-dbs: ["~^test.*"]      # 以 ~ 字符开头,表示规则是正则表达式。
    ​    ignore-dbs: ["mysql"]
        do-tables:
        - db-name: "~^test.*"
          tbl-name: "~^t.*"
        - db-name: "test"
          tbl-name: "t"
        ignore-tables:
        - db-name: "test"
          tbl-name: "log"

    参数解释

    以上参数值以 ~ 开头时均支持使用正则表达式来匹配库名、表名。

    过滤规则

    do-dbsignore-dbs 对应的过滤规则与 MySQL 中的 Evaluation of Database-Level Replication and Binary Logging Options 类似,do-tablesignore-tables 对应的过滤规则与 MySQL 中的 Evaluation of Table-Level Replication Options 类似。

    注意:

    DM 中黑白名单过滤规则与 MySQL 中相应规则存在以下区别:

    • MySQL 中存在 replicate-wild-do-tablereplicate-wild-ignore-table 用于支持通配符,DM 中各配置参数直接支持以 ~ 字符开头的正则表达式。
    • DM 当前只支持 ROW 格式的 binlog,不支持 STATEMENT/MIXED 格式的 binlog,因此应与 MySQL 中 ROW 格式下的规则对应。
    • 对于 DDL,MySQL 仅依据默认的 database 名称(USE 语句显式指定的 database)进行判断,而 DM 优先依据 DDL 中的 database 名称部分进行判断,并当 DDL 中不包含 database 名称时再依据 USE 部分进行判断。假设需要判断的 SQL 为 USE test_db_2; CREATE TABLE test_db_1.test_table (c1 INT PRIMARY KEY),且 MySQL 配置了 replicate-do-db=test_db_1、DM 配置了 do-dbs: ["test_db_1"],则对于 MySQL 该规则不会生效,而对于 DM 该规则会生效。

    判断 table test.t 是否应该被过滤的流程如下:

    1. 首先进行 schema 过滤判断

      • 如果 do-dbs 不为空,判断 do-dbs 中是否存在一个匹配的 schema。

        • 如果存在,则进入 table 过滤判断
        • 如果不存在,则过滤 test.t
      • 如果 do-dbs 为空并且 ignore-dbs 不为空,判断 ignore-dbs 中是否存在一个匹配的 schema。

        • 如果存在,则过滤 test.t
        • 如果不存在,则进入 table 过滤判断
      • 如果 do-dbsignore-dbs 都为空,则进入 table 过滤判断

    2. 进行 table 过滤判断

      1. 如果 do-tables 不为空,判断 do-tables 中是否存在一个匹配的 table。

        • 如果存在,则迁移 test.t
        • 如果不存在,则过滤 test.t
      2. 如果 ignore-tables 不为空,判断 ignore-tables 中是否存在一个匹配的 table。

        • 如果存在,则过滤 test.t.
        • 如果不存在,则迁移 test.t
      3. 如果 do-tablesignore-tables 都为空,则迁移 test.t

    注意:

    如果是判断 schema test 是否应该被过滤,则只进行 schema 过滤判断

    使用示例

    假设上游 MySQL 实例包含以下表:

    `logs`.`messages_2016`
    `logs`.`messages_2017`
    `logs`.`messages_2018`
    `forum`.`users`
    `forum`.`messages`
    `forum_backup_2016`.`messages`
    `forum_backup_2017`.`messages`
    `forum_backup_2018`.`messages`

    配置如下:

    block-allow-list:  # 如果 DM 版本 <= v2.0.0-beta.2 则使用 black-white-list。
      bw-rule:
        do-dbs: ["forum_backup_2018", "forum"]
        ignore-dbs: ["~^forum_backup_"]
        do-tables:
        - db-name: "logs"
          tbl-name: "~_2018$"
        - db-name: "~^forum.*"
    ​      tbl-name: "messages"
        ignore-tables:
        - db-name: "~.*"
    ​      tbl-name: "^messages.*"

    应用 bw-rule 规则后:

    table是否过滤过滤的原因
    logs.messages_2016schema logs 没有匹配到 do-dbs 任意一项
    logs.messages_2017schema logs 没有匹配到 do-dbs 任意一项
    logs.messages_2018schema logs 没有匹配到 do-dbs 任意一项
    forum_backup_2016.messagesschema forum_backup_2016 没有匹配到 do-dbs 任意一项
    forum_backup_2017.messagesschema forum_backup_2017 没有匹配到 do-dbs 任意一项
    forum.users1. schema forum 匹配到 do-dbs,进入 table 过滤判断
    2. schema 和 table 没有匹配到 do-tablesignore-tables 中任意一项,并且 do-tables 不为空,因此过滤
    forum.messages1. schema forum 匹配到 do-dbs,进入 table 过滤判断
    2. schema 和 table 匹配到 do-tablesdb-name: "~^forum.*",tbl-name: "messages"
    forum_backup_2018.messages1. schema forum_backup_2018 匹配到 do-dbs,进入 table 过滤判断
    2. schema 和 table 匹配到 do-tablesdb-name: "~^forum.*",tbl-name: "messages"

    Binlog event filter

    Binlog event filter 是比迁移表黑白名单更加细粒度的过滤规则,可以指定只迁移或者过滤掉某些 schema / table 的指定类型 binlog,比如 INSERTTRUNCATE TABLE

    注意:

    同一个表匹配上多个规则,将会顺序应用这些规则,并且黑名单的优先级高于白名单,即如果同时存在规则 IgnoreDo 应用在某个 table 上,那么 Ignore 生效。

    参数配置

    filters:
      rule-1:
        schema-pattern: "test_*"
        ​table-pattern: "t_*"
        ​events: ["truncate table", "drop table"]
        sql-pattern: ["^DROP\\s+PROCEDURE", "^CREATE\\s+PROCEDURE"]
        ​action: Ignore

    参数解释

    • schema-pattern/table-pattern:对匹配上的上游 MySQL/MariaDB 实例的表的 binlog events 或者 DDL SQL 语句通过以下规则进行过滤。

    • events:binlog events 数组,仅支持从以下 Event 中选择一项或多项。

      Event分类解释
      all代表包含下面所有的 events
      all dml代表包含下面所有 DML events
      all ddl代表包含下面所有 DDL events
      none代表不包含下面所有 events
      none ddl代表不包含下面所有 DDL events
      none dml代表不包含下面所有 DML events
      insertDMLinsert DML event
      updateDMLupdate DML event
      deleteDMLdelete DML event
      create databaseDDLcreate database event
      drop databaseDDLdrop database event
      create tableDDLcreate table event
      create indexDDLcreate index event
      drop tableDDLdrop table event
      truncate tableDDLtruncate table event
      rename tableDDLrename table event
      drop indexDDLdrop index event
      alter tableDDLalter table event
    • sql-pattern:用于过滤指定的 DDL SQL 语句,支持正则表达式匹配,例如上面示例中的 "^DROP\\s+PROCEDURE"

    • action:string (Do / Ignore);进行下面规则判断,满足其中之一则过滤,否则不过滤。

      • Do:白名单。binlog event 如果满足下面两个条件之一就会被过滤掉:
        • 不在该 rule 的 events 中。
        • 如果规则的 sql-pattern 不为空的话,对应的 SQL 没有匹配上 sql-pattern 中任意一项。
      • Ignore:黑名单。如果满足下面两个条件之一就会被过滤掉:
        • 在该 rule 的 events 中。
        • 如果规则的 sql-pattern 不为空的话,对应的 SQL 可以匹配上 sql-pattern 中任意一项。

    使用示例

    过滤分库分表的所有删除操作

    需要设置下面两个 Binlog event filter rule 来过滤掉所有的删除操作:

    • filter-table-rule 过滤掉所有匹配到 pattern test_*.t_* 的 table 的 turncate tabledrop tabledelete statement 操作。
    • filter-schema-rule 过滤掉所有匹配到 pattern test_* 的 schema 的 drop database 操作。
    filters:
      filter-table-rule:
        schema-pattern: "test_*"
        table-pattern: "t_*"
        events: ["truncate table", "drop table", "delete"]
        action: Ignore
      filter-schema-rule:
        schema-pattern: "test_*"
        events: ["drop database"]
        action: Ignore

    只迁移分库分表的 DML 操作

    需要设置下面两个 Binlog event filter rule 只迁移 DML 操作:

    • do-table-rule 只迁移所有匹配到 pattern test_*.t_* 的 table 的 create tableinsertupdatedelete 操作。
    • do-schema-rule 只迁移所有匹配到 pattern test_* 的 schema 的 create database 操作。

    注意:

    迁移 create database/table 的原因是创建库和表后才能迁移 DML

    filters:
      do-table-rule:
        schema-pattern: "test_*"
        table-pattern: "t_*"
        events: ["create table", "all dml"]
        action: Do
      do-schema-rule:
        schema-pattern: "test_*"
        events: ["create database"]
        action: Do

    过滤 TiDB 不支持的 SQL 语句

    可设置如下规则过滤 TiDB 不支持的 PROCEDURE 语句:

    filters:
      filter-procedure-rule:
        schema-pattern: "test_*"
        table-pattern: "t_*"
        sql-pattern: ["^DROP\\s+PROCEDURE", "^CREATE\\s+PROCEDURE"]
        action: Ignore

    过滤 TiDB parser 不支持的 SQL 语句

    对于 TiDB parser 不支持的 SQL 语句,DM 无法解析获得 schema/table 信息,因此需要使用全局过滤规则:schema-pattern: "*"

    注意:

    全局过滤规则的设置必须尽可能严格,以避免过滤掉需要迁移的数据。

    可设置如下规则过滤某些版本的 TiDB parser 不支持的 PARTITION 语句:

    filters:
      filter-partition-rule:
        schema-pattern: "*"
        sql-pattern: ["ALTER\\s+TABLE[\\s\\S]*ADD\\s+PARTITION", "ALTER\\s+TABLE[\\s\\S]*DROP\\s+PARTITION"]
        action: Ignore

    Column mapping

    注意:

    由于 Column mapping 的使用限制较多,不推荐使用 Column mapping 功能作为首选方案。优先推荐的方案可参考 自增主键冲突处理

    Column mapping 提供对表的列值进行修改的功能。可以根据不同的表达式对表的指定列做不同的修改操作,目前只支持 DM 提供的内置表达式。

    注意:

    • 不支持修改 column 的类型和表结构。
    • 不支持对同一个表设置多个不同的列值转换规则。

    参数配置

    column-mappings:
      rule-1:
    ​    schema-pattern: "test_*"
    ​    table-pattern: "t_*"
    ​    expression: "partition id"
    ​    source-column: "id"
    ​    target-column: "id"
    ​    arguments: ["1", "test", "t", "_"]
      rule-2:
    ​    schema-pattern: "test_*"
    ​    table-pattern: "t_*"
    ​    expression: "partition id"
    ​    source-column: "id"
    ​    target-column: "id"
    ​    arguments: ["2", "test", "t", "_"]

    参数解释

    • schema-pattern/table-pattern:对匹配上该规则的上游 MySQL/MariaDB 实例的表按照指定 expression 进行列值修改操作。
    • source-columntarget-column:对 source-column 列的值按照指定 expression 进行修改,将修改后的值赋值给 target-column
    • expression:对数据进行转换的表达式,目前只支持下面的内置计算表达式。

    partition id 表达式

    partition id 用于解决分库分表合并迁移的自增主键的冲突。

    partition id 限制

    注意下面的限制:

    • 只支持类型为 bigint 的列,通常为自增主键、联合主键或者联合唯一索引的其中一列
    • 如果 schema 前缀 不为空,则库名的组成必须为 schema 前缀 或者 schema 前缀 + 分隔符 + 数字(即 schema ID),例如:支持 ss_1,不支持 s_a
    • 如果 table 前缀 不为空,则表名的组成必须为 table 前缀 或者 table 前缀 + 分隔符 + 数字(即 table ID)
    • 如果库名/表名不包含 … + 分隔符 + 数字 部分,则对应的 ID 默认为 0
    • 对分库分表的规模支持限制如下
      • 支持最多 16 个 MySQL/MariaDB 实例,且需要满足 0 <= instance ID <= 15。
      • 每个实例支持最多 128 个 schema,且需要满足 0 <= schema ID <= 127。
      • 每个实例的每个 schema 支持最多 256 个 table,且需要满足 0 <= table ID <= 255。
      • 进行 Column mapping 的列的范围需要满足 0 <= ID <= 17592186044415。
      • {instance ID, schema ID, table ID} 组合需要保持唯一。
    • 目前该功能是定制功能,如果需要调整请联系相关开发人员进行调整

    partition id 参数配置

    用户需要在 arguments 里面按顺序设置以下三个或四个参数:

    • instance_id:客户指定的上游分库分表的 MySQL/MariaDB instance ID(0 <= instance ID <= 15)
    • schema 前缀:用来解析库名并获取 schema ID
    • table 前缀:用来解释表名并获取 table ID
    • 分隔符:用来分隔前缀与 ID,可省略,省略时分隔符默认为空字符串

    instance_idschema 前缀table 前缀 这三个参数均可被设置为空字符串(""),表示对应的部分不会被编码进 partition id

    partition id 表达式规则

    partition id 会用 arguments 里面的数字来填充自增主键 ID 的首个比特位,计算出来一个 int64(即 MySQL bigint)类型的值,具体规则如下:

    instance_idschema 前缀table 前缀编码
    ☑ 已定义☑ 已定义☑ 已定义[S: 1 比特位][`I`: 4 比特位] [D: 7 比特位][`T`: 8 比特位] [P: 44 比特位]
    ☐ 空☑ 已定义☑ 已定义[S: 1 比特位][`D`: 7 比特位] [T: 8 比特位][`P`: 48 比特位]
    ☑ 已定义☐ 空☑ 已定义[S: 1 比特位][`I`: 4 比特位] [T: 8 比特位][`P`: 51 比特位]
    ☑ 已定义☑ 已定义☐ 空[S: 1 比特位][`I`: 4 比特位] [D: 7 比特位][`P`: 52 比特位]
    ☐ 空☐ 空☑ 已定义[S: 1 比特位][`T`: 8 比特位] [P: 55 比特位]
    ☐ 空☑ 已定义☐ 空[S: 1 比特位][`D`: 7 比特位] [P: 56 比特位]
    ☑ 已定义☐ 空☐ 空[S: 1 比特位][`I`: 4 比特位] [P: 59 比特位]
    • S:符号位,保留
    • I:instance ID,默认 4 比特位
    • D:schema ID,默认 7 比特位
    • T:table ID,默认 8 比特位
    • P:自增主键 ID,占据剩下的比特位(≥44 比特位)

    使用示例

    假设存在分库分表场景:将上游两个 MySQL 实例的 test_{1,2,3...}.t_{1,2,3...} 迁移到下游 TiDB 的 test.t,并且这些表都有自增主键。

    需要设置下面两个规则:

    column-mappings:
      rule-1:
    ​    schema-pattern: "test_*"
    ​    table-pattern: "t_*"
    ​    expression: "partition id"
    ​    source-column: "id"
    ​    target-column: "id"
    ​    arguments: ["1", "test", "t", "_"]
      rule-2:
    ​    schema-pattern: "test_*"
    ​    table-pattern: "t_*"
    ​    expression: "partition id"
    ​    source-column: "id"
    ​    target-column: "id"
    ​    arguments: ["2", "test", "t", "_"]
    • MySQL instance 1 的表 test_1.t_1ID = 1 的行经过转换后,ID = 1 变为 1 << (64-1-4) | 1 << (64-1-4-7) | 1 << 44 | 1 = 580981944116838401
    • MySQL instance 2 的表 test_1.t_2ID = 1 的行经过转换后,ID = 2 变为 2 << (64-1-4) | 1 << (64-1-4-7) | 2 << 44 | 2 = 1157460288606306306

    online DDL 工具支持

    在 MySQL 生态中,gh-ost 与 pt-osc 等工具较广泛地被使用,DM 对其提供了特殊的支持以避免对不必要的中间数据进行迁移。

    有关 DM 对 online DDL 工具支持的原理、处理流程等,可参考 online-ddl-scheme

    使用限制

    • DM 仅针对 gh-ost 与 pt-osc 做了特殊支持。
    • 在开启 online-ddl-scheme 时,增量复制对应的 checkpoint 应不处于 online DDL 执行过程中。如上游某次 online DDL 操作开始于 binlog position-A、结束于 position-B,则增量复制的起始点应早于 position-A 或晚于 position-B,否则可能出现迁移出错,具体可参考 FAQ

    参数配置

    如上游 MySQL/MariaDB 使用的是 gh-ost 工具,则在 task 的配置文件中设置:

    online-ddl-scheme: "gh-ost"

    如上游 MySQL/MariaDB 使用的是 pt-osc 工具,则在 task 的配置文件中设置:

    online-ddl-scheme: "pt"

    分库分表合并

    DM 支持将上游 MySQL/MariaDB 各分库分表中的 DML、DDL 数据合并后迁移到下游 TiDB 的库表中。

    使用限制

    目前分库分表合并功能仅支持有限的场景,使用该功能前,请仔细阅读悲观模式分库分表合并迁移使用限制乐观模式分库分表合并迁移使用限制

    参数配置

    在 task 的配置文件中设置:

    shard-mode: "pessimistic" # 如果为分库分表合并任务则需要配置该项。默认使用悲观协调模式 "pessimistic",在深入了解乐观协调模式的原理和使用限制后,也可以设置为乐观协调模式 "optimistic"

    手动处理 Sharding DDL Lock

    如果分库分表合并迁移过程中发生了异常,对于部分场景,可尝试参考手动处理 Sharding DDL Lock进行处理。