DM 分库分表合并场景

本文介绍如何在分库分表合并场景中使用 Data Migration (DM)。

下面介绍了一个简单的场景,两个数据源 MySQL 实例的分库和分表数据需要迁移至下游 TiDB 集群。更多详情请参阅分表合并数据迁移最佳实践

数据源实例

假设数据源结构如下:

  • 实例 1

    | Schema | Tables | |:———|:———| | user | information, log_bak | | store_01 | sale_01, sale_02 | | store_02 | sale_01, sale_02 |

  • 实例 2

    | Schema | Tables | |:———|:———| | user | information, log_bak | | store_01 | sale_01, sale_02 | | store_02 | sale_01, sale_02 |

迁移需求

  1. user.information 需要合并到下游 TiDB 中的 user.information 表。
  2. 实例中的 store_{01|02}.sale_{01|02} 表合并至下游 TiDB 中的 store.sale 表。
  3. 同步 userstore_{01|02} 库,但不同步两个实例的 user.log_bak 表。
  4. 过滤掉两个实例中 store_{01|02}.sale_{01|02} 表的所有删除操作,并过滤该库的 drop database 操作。

预期迁移后下游库结构如下:

Schema Tables
user information
store sale

分表数据冲突检查

迁移需求 #1 和 #2 涉及合库合表,来自多张分表的数据可能引发主键或唯一索引的数据冲突。这需要我们检查这几组分表数据的业务特点,详情请见跨分表数据在主键或唯一索引冲突处理。在本示例中:

user.information 表结构为

  1. CREATE TABLE `information` (
  2. `id` bigint(20) NOT NULL AUTO_INCREMENT,
  3. `uid` bigint(20) DEFAULT NULL,
  4. `name` varchar(255) DEFAULT NULL,
  5. `data` varchar(255) DEFAULT NULL,
  6. PRIMARY KEY (`id`),
  7. UNIQUE KEY `uid` (`uid`)
  8. ) ENGINE=InnoDB DEFAULT CHARSET=latin1

其中 id 列为主键,uid 列为唯一索引。id 列具有自增属性,多个分表范围重复会引发数据冲突。 uid 可以保证全局满足唯一索引,因此可以按照参考去掉自增主键的主键属性中介绍的操作绕过 id 列。

store_{01|02}.sale_{01|02} 的表结构为

  1. CREATE TABLE `sale_01` (
  2. `sid` bigint(20) NOT NULL,
  3. `pid` bigint(20) NOT NULL,
  4. `comment` varchar(255) DEFAULT NULL,
  5. PRIMARY KEY (`sid`),
  6. KEY `pid` (`pid`)
  7. ) ENGINE=InnoDB DEFAULT CHARSET=latin1

其中 sid 是分片键,可以保证同一个 sid 只会划分到一个分表中,因此不会引发数据冲突,无需进行额外操作。

迁移方案

  • 要满足迁移需求 #1,无需配置 table routing 规则。按照去掉自增主键的主键属性的要求,在下游手动建表。

    1. CREATE TABLE `information` (
    2. `id` bigint(20) NOT NULL AUTO_INCREMENT,
    3. `uid` bigint(20) DEFAULT NULL,
    4. `name` varchar(255) DEFAULT NULL,
    5. `data` varchar(255) DEFAULT NULL,
    6. INDEX (`id`),
    7. UNIQUE KEY `uid` (`uid`)
    8. ) ENGINE=InnoDB DEFAULT CHARSET=latin1

    并在配置文件中跳过前置检查

    1. ignore-checking-items: ["auto_increment_ID"]
  • 要满足迁移需求 #2,配置 table routing 规则如下:

    1. routes:
    2. ...
    3. store-route-rule:
    4. schema-pattern: "store_*"
    5. target-schema: "store"
    6. sale-route-rule:
    7. schema-pattern: "store_*"
    8. table-pattern: "sale_*"
    9. target-schema: "store"
    10. target-table: "sale"
  • 要满足迁移需求 #3,配置 Block & Allow Lists 如下:

    1. block-allow-list:
    2. log-bak-ignored:
    3. do-dbs: ["user", "store_*"]
    4. ignore-tables:
    5. - db-name: "user"
    6. tbl-name: "log_bak"
  • 要满足迁移需求 #4,配置 Binlog event filter 规则如下:

    1. filters:
    2. ...
    3. sale-filter-rule: # 过滤掉 store_* 库下面任何表的任何删除操作
    4. schema-pattern: "store_*"
    5. table-pattern: "sale_*"
    6. events: ["truncate table", "drop table", "delete"]
    7. action: Ignore
    8. store-filter-rule: # 过滤掉删除 store_* 库的操作
    9. schema-pattern: "store_*"
    10. events: ["drop database"]
    11. action: Ignore

迁移任务配置

迁移任务的完整配置如下,更多详情请参阅数据迁移任务配置向导

  1. name: "shard_merge"
  2. task-mode: all # 进行全量数据迁移 + 增量数据迁移
  3. meta-schema: "dm_meta"
  4. ignore-checking-items: ["auto_increment_ID"]
  5. target-database:
  6. host: "192.168.0.1"
  7. port: 4000
  8. user: "root"
  9. password: ""
  10. mysql-instances:
  11. -
  12. source-id: "instance-1" # 数据源对象 ID,可以从数据源配置中获取
  13. route-rules: ["store-route-rule", "sale-route-rule"] # 应用于该数据源的 table route 规则
  14. filter-rules: ["store-filter-rule", "sale-filter-rule"] # 应用于该数据源的 binlog event filter 规则
  15. block-allow-list: "log-bak-ignored" # 应用于该数据源的 Block & Allow Lists 规则
  16. -
  17. source-id: "instance-2"
  18. route-rules: ["store-route-rule", "sale-route-rule"]
  19. filter-rules: ["store-filter-rule", "sale-filter-rule"]
  20. block-allow-list: "log-bak-ignored"
  21. # 所有实例共享的其他通用配置
  22. routes:
  23. store-route-rule:
  24. schema-pattern: "store_*"
  25. target-schema: "store"
  26. sale-route-rule:
  27. schema-pattern: "store_*"
  28. table-pattern: "sale_*"
  29. target-schema: "store"
  30. target-table: "sale"
  31. filters:
  32. sale-filter-rule:
  33. schema-pattern: "store_*"
  34. table-pattern: "sale_*"
  35. events: ["truncate table", "drop table", "delete"]
  36. action: Ignore
  37. store-filter-rule:
  38. schema-pattern: "store_*"
  39. events: ["drop database"]
  40. action: Ignore
  41. block-allow-list:
  42. log-bak-ignored:
  43. do-dbs: ["user", "store_*"]
  44. ignore-tables:
  45. - db-name: "user"
  46. tbl-name: "log_bak"