DM同步为已有迁移任务增加新同步的表

感谢 @seiang 的贡献

DM 是一款便捷的数据迁移工具,支持从与 MySQL 协议兼容的数据库(MySQL、MariaDB、Aurora MySQL)到 TiDB 的全量数据迁移和增量数据同步。使用 DM 工具有利于简化数据迁移过程,降低数据迁移运维成本。

DM 除了在MySQL迁移TiDB过程中发挥着重要的作用,而且在将上游MySQL数据近实时同步到TiDB集群做AP复杂查询也发挥着重要的作用;

在实际的数据同步场景中,经常会遇到已有数据同步任务正在运行,但又有上游 MySQL 其他新的表需要添加到该迁移任务中;本文针对已有的DM同步任务,如何为该同步任务添加新的同步的表?

下面是官方文档 中,针对已有数据迁移任务所处不同阶段的处理方案:

1、迁移任务当前处于 Dump 阶段

由于 MySQL 不支持指定 snapshot 来进行导出,因此在导出过程中不支持更新迁移任务并重启以通过断点继续导出,故无法支持在该阶段动态增加需要迁移的表。

如果确实需要增加其他的表用于迁移,建议直接使用新的配置文件重新启动迁移任务。

2、迁移任务当前处于 Load 阶段

多个不同的数据迁移任务在导出时,通常对应于不同的 binlog position,如将它们在 Load 阶段合并导入,则无法就 binlog position 达成一致,因此不建议在 Load 阶段向数据迁移任务中增加需要迁移的表。

3、迁移任务当前处于 Sync 阶段

当数据迁移任务已经处于 Sync 阶段时,在配置文件中增加额外的表并重启任务,DM 并不会为新增的表重新执行全量导出与导入,而是会继续从之前的断点进行增量复制。

因此,如果需要新增的表对应的全量数据尚未导入到下游,则需要先使用单独的数据迁移任务将其全量数据导出并导入到下游。

将已有迁移任务对应的全局 checkpoint (is_global=1)中的 position 信息记为 checkpoint-T,如 (mysql-bin.000100, 1234)。将需要增加到迁移任务的表在全量导出的 metedata(或另一个处于 Sync 阶段的数据迁移任务的 checkpoint)的 position 信息记为 checkpoint-S,如 (mysql-bin.000099, 5678)。则可通过以下步骤将表增加到迁移任务中:

  • 需要更新的 checkpoint 表为 {dm_meta} 库中的 {task-name}_syncer_checkpoint。
  • 需要更新的 checkpoint 行为 id={source-id} 且 is_global=1。
  • 需要更新的 checkpoint 列为 binlog_name 与 binlog_pos。
  1. 使用 stop-task 停止已有迁移任务。如果需要增加的表属于另一个运行中的迁移任务,则也将其停止。
  2. 使用 MySQL 客户连接到下游 TiDB 数据库,手动更新已有迁移任务对应的 checkpoint 表中的信息为 checkpoint-T 与 checkpoint-S 中的较小值(在本例中,为 (mysql-bin.000099, 5678))。
  3. 在迁移任务配置中为 syncers 部分设置 safe-mode: true 以保证可重入执行。
  4. 通过 start-task 启动迁移任务。
  5. 通过 query-status 观察迁移任务状态,当 syncerBinlog 超过 checkpoint-T 与 checkpoint-S 中的较大值后(在本例中,为 (mysql-bin.000100, 1234)),即可还原 safe-mode 为原始值并重启迁移任务。

下文是结合官方文档提供的方案和实际业务中为已有的数据同步添加新表的实践案例:

需求:

目前某业务库已经有DM同步任务从上游MySQL中同步数据到TiDB集群,该同步任务重同步的表数据数量是56张,接下来由于业务迭代,需要新增两张表(user2gameapp users_info)从上游MySQL同步到TiDB集群中;

已存在DM同步任务配置文件如下:

name: "tidb-xxx-task"
case-sensitive: true
meta-schema: "dm_meta"
task-mode: "all"


target-database:
  host: "10.xx.xx.xx"
  port: 4000
  user: "syncuser"
  password: "xxxxxxxxxxxx"


mysql-instances:
  -
   source-id: "mysql-xxx"
   block-allow-list: "global"
   route-rules: ["mysql-xxx-rule"]     
   mydumper-config-name: "global"        
   loader-config-name: "global"           
   syncer-config-name: "global"            


block-allow-list:
  global:                            
    do-dbs: ["RTXXX"]                          
    do-tables:
    - db-name: "RTXXX"   
      tbl-name: "xxx1_game"
    - db-name: "RTXXX"   
      tbl-name: "xxx2_game"
    - db-name: "RTXXX"   
      tbl-name: "xxx_ad"
   .....


routes:
    mysql-xxx-rule:
      schema-pattern: "RTXXX"
      target-schema: "RTXXX_TiDB"
        
mydumpers:
  global:                           
    threads: 4
        
loaders:                           
  global:
    pool-size: 16
        
syncers:                            
  global:                            
    worker-count: 16
    batch: 100

操作流程

1、通过dumpling导出上游MySQL要新增同步的了两张表

# dumpling -h 10.xx.xx.xx -P 3306 -uxxxx -p --filetype sql -t 8 -F 64MiB -B RTXXX -T $(cat /data/xx.lst)  -o /data/RTXXX

2、查看导出的SQL文件的metadata记录,后面修改全局 checkpoint会用到

# cat metadata
Started dump at: 2022-04-28 12:19:43
SHOW MASTER STATUS:
        Log: mysqlbin.025306
        Pos: 615988532
        GTID:27a0991c-b504-11ea-9bc4-005056b73203:1-5220,
c492d887-b503-11ea-8362-005056b7b179:1-1665110007

SHOW SLAVE STATUS:
        Host: 10.xx.xx.xx
        Log: mysqlbin.025403
        Pos: 616318608
        GTID:27a0991c-b504-11ea-9bc4-005056b73203:1-5220,
c492d887-b503-11ea-8362-005056b7b179:1-1665110007
Finished dump at: 2022-04-28 12:19:44

3、将导出的SQL文件通过tidb-lightning导入到TiDB集群

tidb-lightning配置文件如下:

# cat tidb-lightning.toml
[lightning]
level = "info"
file = "/xxx/tidb-lightning.log"
pprof-port = 8289
status-addr = '0.0.0.0:8289'


[tikv-importer]
backend = "tidb"
on-duplicate = "error"


[mydumper]

read-block-size = 65536
batch-size = 1262485504
data-source-dir = "/data/RTXXX"
no-schema = false

filter = ['*.*', '!mysql.*', '!sys.*', '!INFORMATION_SCHEMA.*', '!PERFORMANCE_SCHEMA.*', '!METRICS_SCHEMA.*', '!INSPECTION_SCHEMA.*']


[tidb]

host = "10.xx.xx.xx"
port = 4000
user = "syncuser"
password = "xxxxxxx"
status-port = 10080
pd-addr = "10.xx.xx.xx:2379"


[checkpoint]

enable = true


导入数据

# nohup tidb-lightning -config /xxx/tidb-lightning.toml > nohup.out &

4、上述数据导入完成后,停掉已存在同步任务

$ tiup dmctl --master-addr 10.xx.xx.xx:8261 stop-task tidb-xxx-task   
Starting component `dmctl`: /home/tidb/.tiup/components/dmctl/v2.0.4/dmctl/dmctl --master-addr 10.xx.xx.xx:8261 stop-task tidb-xxx-task 
{
    "op": "Stop",
    "result": true,
    "msg": "",
    "sources": [
        {
            "result": true,
            "msg": "",
            "source": "mysql-xxx",
            "worker": "dm-10.xx.xx.xx-8262"
        }
    ]
}

5、修改 {dm_meta} 库中的 {task-name}_syncer_checkpoint

mysql> select * from `tidb-xxx-task_syncer_checkpoint` where is_global=1\G
*************************** 1. row ***************************
                   id: mysql-xxx
            cp_schema:
             cp_table:
          binlog_name: mysqlbin.025306
           binlog_pos: 720283200
          binlog_gtid: 27a0991c-b504-11ea-9bc4-005056b73203:1-5220,c492d887-b503-11ea-8362-005056b7b179:1-1665117758
exit_safe_binlog_name:
exit_safe_binlog_pos: 0
exit_safe_binlog_gtid:
           table_info: null
            is_global: 1
          create_time: 2022-04-28 11:32:31
          update_time: 2022-04-28 12:30:47
1 row in set (0.02 sec)

修改全局的checkpoint,主要如果开启了GTID,这里也是需要修改GTID的

mysql> update `tidb-xxx-task_syncer_checkpoint` set binlog_name='mysqlbin.025306',binlog_pos='615988532',binlog_gtid='27a0991c-b504-11ea-9bc4-005056b73203:1-5220,c492d887-b503-11ea-8362-005056b7b179:1-1665110007' where is_global=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

6、修改DM同步任务的配置文件,将新增的两张同步表添加到配置文件中

name: "tidb-xxx-task"
case-sensitive: true
meta-schema: "dm_meta"
task-mode: "all"


target-database:
  host: "10.xx.xx.xx"
  port: 4000
  user: "syncuser"
  password: "xxxxxxxxxxxx"


mysql-instances:
  -
   source-id: "mysql-xxx"
   block-allow-list: "global"
   route-rules: ["mysql-xxx-rule"]     
   mydumper-config-name: "global"        
   loader-config-name: "global"           
   syncer-config-name: "global"            


block-allow-list:
  global:                            
    do-dbs: ["RTXXX"]                          
    do-tables:
    - db-name: "RTXXX"   
      tbl-name: "xxx1_game"
    - db-name: "RTXXX"   
      tbl-name: "xxx2_game"
    - db-name: "RTXXX"   
      tbl-name: "xxx_ad"
    - db-name: "RTXXX"
      tbl-name: "user2gameapp"
    - db-name: "RTXXX"
      tbl-name: "users_info"

   .....


routes:
    mysql-xxx-rule:
      schema-pattern: "RTXXX"
      target-schema: "RTXXX_TiDB"
        
mydumpers:
  global:                           
    threads: 4
        
loaders:                           
  global:
    pool-size: 16
        
syncers:                            
  global:                            
    worker-count: 16
    batch: 100

7、重新启动同步任务

$ tiup dmctl --master-addr 10.xx.xx.xx:8261 start-task ./task_xxx.yaml
Starting component `dmctl`: /home/tidb/.tiup/components/dmctl/v2.0.4/dmctl/dmctl --master-addr 10.xx.xx.xx:8261 start-task ./task_xxx.yaml
{
    "result": true,
    "msg": "",
    "sources": [
        {
            "result": true,
            "msg": "",
            "source": "mysql-xxx",
            "worker": "dm-10.xx.xx.xx-8262"
        }
    ]
}

8、查看同步任务状态

$ tiup dmctl --master-addr 10.xx.xx.xx:8261 query-status tidb-xxx-task
Starting component `dmctl`: /home/tidb/.tiup/components/dmctl/v2.0.4/dmctl/dmctl --master-addr 10.xx.xx.xx:8261 query-status tidb-xxx-task
{
    "result": true,
    "msg": "",
    "sources": [
        {
            "result": true,
            "msg": "",
            "sourceStatus": {
                "source": "mysql-xxx",
                "worker": "dm-10.xx.xx.xx-8262",
                "result": null,
                "relayStatus": null
            },
            "subTaskStatus": [
                {
                    "name": "tidb-xxx-task",
                    "stage": "Running",
                    "unit": "Sync",
                    "result": null,
                    "unresolvedDDLLockID": "",
                    "sync": {
                        "totalEvents": "292390",
                        "totalTps": "9702",
                        "recentTps": "9702",
                        "masterBinlog": "(mysqlbin.025307, 28133809)",
                        "masterBinlogGtid": "27a0991c-b504-11ea-9bc4-005056b73203:1-5220,c492d887-b503-11ea-8362-005056b7b179:1-1665124398",
                        "syncerBinlog": "(mysqlbin.025307, 27748593)",
                        "syncerBinlogGtid": "27a0991c-b504-11ea-9bc4-005056b73203:1-5220,c492d887-b503-11ea-8362-005056b7b179:1-1665124326",
                        "blockingDDLs": [
                        ],
                        "unresolvedGroups": [
                        ],
                        "synced": false,
                        "binlogType": "remote",
                        "secondsBehindMaster": "0"
                    }
                }
            ]
        }
    ]
}

到此,为已存在的DM同步任务添加新的同步表的操作就全部完成了;

笔者能力有限,文章中如果存在技术性或描述性等错误,请大家及时指正,非常感谢!