DM修改task的block-allow-list之后无法同步新表

为提高效率,请提供以下信息,问题描述清晰能够更快得到解决:

【TiDB 版本】
tidb版本为v5.0.0
DM版本为v2.0.1
【问题描述】
任务模式为“all”,因为我测试的场景是全量+增量

task.yaml关键配置大致如下:

    task-mode: "all"
    mysql-instances:
    - source-id: "dev-a-mysql-slave-replica"
      block-allow-list: "test-rule"
    block-allow-list:
      test-rule:
        do-dbs: ["push"]
        do-tables:
        - db-name: "push"
          tbl-name: "user"
  1. 此时首次start-task后可以发现user表新建并同步了存量的n条数据。是符合正常期望的

  2. 之后将 tbl-name: "user"修改为 tbl-name: “abc”,发现下游tidb中并未新建并同步abc表的数据

  3. 去dm-worker的log文件可看到如下关键日志:
    [2021/04/11 08:48:07.904 +00:00] [ERROR] [baseconn.go:106] [“query statement failed”] [task=test] [unit=“binlogreplication”] [query=“SHOW CREATE TABLE push.user”] [argument="[]"] [error=“Error 1146: Table ‘push.user’ doesn’t exist”]
    [2021/04/11 08:48:07.905 +00:00] [ERROR] [db.go:199] [“query statement failed after retry”] [task=test] [unit=“binlog replication”] [query=“SHOW CREATE TABLE push.user”] [argument="[]"] [error="[code=10005:class=database:scope=not-set:level=high], Message: query statement failed: SHOW CREATE TABLE push.user, RawCause: Error 1146: Table ‘push.user’ doesn’t exist"]

  4. query-status test的结果如下
    {
    “result”: true,
    “msg”: “”,
    “sources”: [
    {
    “result”: true,
    “msg”: “”,
    “sourceStatus”: {
    “source”: “dev-a-mysql-slave-replica”,
    “worker”: “dm-10.10.52.20-8262”,
    “result”: null,
    “relayStatus”: null
    },
    “subTaskStatus”: [
    {
    “name”: “test”,
    “stage”: “Running”,
    “unit”: “Sync”,
    “result”: null,
    “unresolvedDDLLockID”: “”,
    “sync”: {
    “totalEvents”: “0”,
    “totalTps”: “0”,
    “recentTps”: “0”,
    “masterBinlog”: “(mysql-bin.000283, 787902482)”,
    “masterBinlogGtid”: “72ce558a-7c0c-11e7-8117-fa163eaf8427:244995526-279418205:279418207-279498776:279498778-279505474:279505476-279505568:279505570-279533138:279533140-279536477:279536479-279546364:279546366-279546508:279546510-288522397:288522399-743419229,ddffec79-c444-11e7-9807-fa163ef5cb4b:1-97”,
    “syncerBinlog”: “(mysql-bin.000283, 787800006)”,
    “syncerBinlogGtid”: “72ce558a-7c0c-11e7-8117-fa163eaf8427:244995526-279418205:279418207-279498776:279498778-279505474:279505476-279505568:279505570-279533138:279533140-279536477:279536479-279546364:279546366-279546508:279546510-288522397:288522399-743419041,ddffec79-c444-11e7-9807-fa163ef5cb4b:1-97”,
    “blockingDDLs”: [
    ],
    “unresolvedGroups”: [
    ],
    “synced”: false,
    “binlogType”: “remote”
    }
    }
    ]
    }
    ]
    }

  5. 此时我手动在tidb去执行create table abc的DDL,再start-task,发现abc表记录同步过来了
    【疑问】
    我的期望是同步表从user改abc后(或者user也保留,增加一个abc表),能够自动创建abc并其同步存量记录,而目前似乎只有首次start-task的配置的库表才会自动新建? 之后stop-task+改task.yaml文件+start-task的新增库表是无法自动新建的? 能详细阐述下这类用法官方推荐是什么样的吗,谢谢

先梳理下你这边的步骤

首先同步的是 tbl-name: “user” 同步正常。

停掉同步任务之后,想要同步 tbl-name: “abc” 这个表,但其实上游不存在该表。不存在的表写在 同步任务里是什么样的需求呢 ?

上游不存在的表,配置在 task 中启动,报错 error=“Error 1146: Table ‘push.user’ doesn’t exist 这是预期的行为。

新增表同步可以参考官网
https://docs.pingcap.com/zh/tidb-data-migration/stable/faq#如何为已有迁移任务增加需要迁移的表

谢谢小王同学回答。

上游mysql是存在该表的。提示log中报的应是下游tidb不存在abc表。所以我是说下游tidb在处理abc表时为何没像首次start-task的user表那样自动create并同步数据

哦 这个问题可以看下下游 dm_meta 的 checkpoint 信息,这个 checkpoint 是全局的,并不是表级别的。比如 在 t1 时间修改 task 新增一个表,该表在 t0 之前创建,重启 task 也只会在 t1 断点续传,从 t1 开始同步 新表的数据,但是 新表的表结构未在下游创建,会导致同步出错。上面 官网链接中也有提到哈。

我读完了,理解一下。

所以解决方案是2种

  1. 要么创建一个新的task,去迁移新增的表?
  2. 要么通过文档中所述回退binlog_name和binlog_position的思路,让已有Task重新处理一遍包含新表的binlog?

是的。

小王同学,第二种我试了下,还是不行。我说下大致过程:

  1. 之前task.yaml有user表,而目前abc表有1条记录(如id=1),此时假设binlog_name=mysql-bin.000001 & binlog_position=100。我stop-task
  2. abc表新增第2条记录(如id=2),假设binlog_name=mysql-bin.000001 & binlog_position=120
  3. 我在task.yml中新增abc表,增加syncers的safe-mode: true。并且手动在下游tidb执行DDL:create table abc。并且将{task-name}_syncer_checkpoint的is_global=1的唯一的source-id记录,修改其binlog_name=mysql-bin.000001 & binlog_position=100(即步骤1时的值)
  4. 此时start-task继续开始任务。

此时我的预期是按以上操作后,dm任务能将abc表将id=2的记录同步过来。但是并没有,abc表是空的,然后我在上游mysql新增了第3条记录(id=3)时,下游倒是同步了id=3的记录。

所以是我对文档理解有误吗?我该如何操作呢?

文档中推荐方式是 先进行全量数据导入,然后再去更新 checkpoint 信息,这样操作看看呢。

相当于新表abc的存量数据,新建1个全量数据导入的taskA来处理。然后在原user表的taskB加上abc表,并且将taskB的is_global所在记录,回退至全量导入任务taskA所在的binlog_name & binlog_position,相当于处理全量taskA后的增量?

是的。

还是不行。我说下我的步骤:

  1. 之前task.yaml有user表,而目前abc表有1条记录(如id=1)。我新建task-abc.yaml(task-mode设为full)全量同步。此时query-status task-abc假设binlog_name=mysql-bin.000001 & binlog_position=100。可以发现abc表id=1的记录同步到tidb了

  2. stop-task task.yaml。并且编辑task.yaml增加abc表以及syncers的safe-mode: true。此时假设{task-name}_syncer_checkpoint的is_global=1为binlog_name=mysql-bin.000001 & binlog_position=110。我取较小值binlog_position=100更新到is_global=1记录。

  3. 此时abc表新增第2条记录(如id=2),start-task task.yaml继续开始任务

此时我的预期是按以上操作后。task任务能将关闭期间abc表新增id=2的记录同步到tidb,最终tidb有id=1和id=2的记录。但是结果是id=2的没有。 此时我在上游mysql新增了第3条记录(id=3)时,下游倒是同步了id=3的记录。

里面出了什么问题,我应该是完全按照文档要求操作了吧

看描述,没有先全量导入数据吧,不是用你这个task任务,可以重启一个任务导入,或者就简单的dumpling,lightning 导入到 tidb 全量数据就行。

明白,如我最新的这条描述,我已经用新任务成功导入了存量数据id=1了。现在的问题是,全量导入后~旧任务加入新表再start的 期间还有会一些增量数据,我这部分数据用文档的方法没成功同步过来

  1. 新表导入的过程中,task 停止了吗? 如果没有停止,一直增量同步,那增量同步过程的新表的数据没法同步。
  2. 如果原任务不能停止,或者你就完全直接新启动一个task同步新表也可以。

旧task.yaml停止了的,并且按文档说的回退到了全量同步完成时的binlog_name和binlog_position,再重新start-task 旧task.yaml

创建task同步表A---->停止task----> 全量导入表B---->修改task,包含表B----> 再启动 task ,是这样吗?如果是,可以重新操作一下。

应该是全量导入表B后,再停task哦,否则task停止时间还得等全量导完B的时间(比如B表是大表要同步5小时,task就得停至少5小时)

官网文档写的意思是停了task后,把task任务的checkpoint回滚到表B全量同步结束时,再启动task任务

小王同学。能帮我确认下是不是{task-name}_syncer_checkpoint中的binlog_gtid也要更新(官网文档只说了binlog_name & binlog_position ),我发现把binlog_gtid也更新,就可以达到我期望效果了!
即之前回滚的sql一直是:
update test_syncer_checkpoint set binlog_name=‘mysql-bin.000285’,binlog_pos = 597648319 where is_global=‘1’;
成功的是回滚sql变成了:
update test_syncer_checkpoint set binlog_name=‘mysql-bin.000285’,binlog_pos = 597648319,binlog_gtid=‘ddffec79-c444-11e7-9807-fa163ef5cb4b:1-97,xxxxxxxxxx’ where is_global=‘1’;
(另外set binlog_gtid=’'或binlog_gtid=null也不行)

确认下,你开启 GTID 同步了吗?

开了的,开了回滚步骤时是不是就有涉及is_global的gtid的操作了,还请详细介绍下,官方文档完全没提