DM同步频繁报错主键冲突问题,但实际没有冲突

mysql同步到tidb一次在线DDL的时候。因为tidb已经提前加过了索引,跳过错误,或者(之前测试)他会自动跳过。但是这个任务他手动执行跳过之后频繁报错主键冲突,但实际上没有冲突,手动resume-task 恢复他就正常同步了。到那时过十几分钟工半小时他就会又提示冲突


手动resume的时候,确认一下binlog位置是不是回退了,有可能是回退之后,重新同步到问题点重复触发了相同的报错现象。

另外可以新起一个同步任务,同步到下游没有提前创建主键的表,看看是不是这个原因导致的问题。

https://docs.pingcap.com/zh/tidb/stable/dm-safe-mode#dm-安全模式

DM 从 checkpoint 恢复数据同步任务后,可能重复执行某些 binlog 事件而导致下述问题:

  1. 在进行增量同步过程中,执行 DML 的操作和写 checkpoint 的操作并不是同步的;写 checkpoint 的操作和写下游数据的操作也并不能保证原子性。因此,当 DM 异常退出时,checkpoint 可能只记录到退出时刻之前的一个恢复点
  2. 当 DM 重启同步任务,并从 checkpoint 重新开始增量数据同步时,checkpoint 之后的部分数据可能已经在异常退出前被处理过了,从而导致部分 SQL 语句重复执行
  3. 如果重复执行 INSERT 操作,会导致主键或唯一索引冲突,引发同步中断;如果重复执行 UPDATE 操作,会导致不能根据筛选条件找到之前对应的更新记录。

这个问题在安全模式这段里面有所论述。
安全模式可以解决这个问题。

而且安全模式有自动开启的机制

当 DM 从 checkpoint 恢复增量同步任务(例如 worker 重启,网络中断重连等)时,会自动开启一段时间的安全模式。

我推测你每次resume之后又好了,可能就是这个自动开启的安全模式短时间自动改写了冲突的sql。运行一段时间安全模式退出,然后碰上下一个冲突的sql,就又报错停下了。

1 个赞

大概率是这个问题,建议用sync-diff工具对比一下报错的表,看一下上下游数据是否一致

1 个赞

他是一直在同步。同步到1个点,然后提示冲突,但是冲突的数据在tidb查是没有的。然后手动resume,他继续同步,根据同步的进度感觉是回退了。然后同步十几分钟之后。他就又会出现相同问题,还要继续手动resume,除非实时同步了。他才不会出问题。如果有操作大事务延迟了。他再追日志的时候就会频繁报这个错误

这个是增量同步的过滤delte,目标tidb要全量数据,源端只有近几个月的数据,这个已经是新启的一个任务了

会不会是冲突的数据在一个事务里,然后事务失败了就都回滚了?

然后这可能就是在一个事务内也会冲突的原因了。可能是开启了一个大事务,对一条数据插入->删除->再插入。因为你过滤掉了delete事件,那么在下游就会出现同一个事务中的数据被插入2次。

这么看最好的解决方案也只能是dm开启安全模式。sync-diff因为上下游的表数据本来也不同步,所以也没有办法对比一致性。

对比一下数据

上游不可能人工删除数据的。这些都是属于订单数据,而且他不是一直都冲突,只有在延迟1小时以上。开始追的时候才10十几分钟提示一个冲突,然后点击恢复,就直接继续同步没有这个错误了。
因为春节期间我在订单库有加索引和其他大事务操作。所以有两三次他延迟几个小时的,只要延迟几个小时,他就会提示有主键冲突,但是只要延迟在3分钟内。也就是实时同步正常了。他就不会出现这个问题。

现在几乎没有大事务操作。所以目前实时同步中,不会出现问题了。
就是想了解下问什么会有这个问题,冲突他提示的sql是一个insert,而且他不会是同一个事务有大量insert。
而且也不会在一个事务里面isnert然后删除在insert。他是订单数据库几乎不可能有业务删除,他是停车场进出场的数据,只有insert和update。

是多个源吗?

1 个赞

只有一个

mysql ddl 是直接执行的还是用工具执行的

这个ddl是使用gh-ost执行的。我有添加在线ddl参数,还添加了过滤create index的参数。但是gh-ost是内部生成转换的create index 所以他还是会执行。所以报错。我执行跳过。这个错误,没有问题。开始同步。不过他会频繁提示主键冲突,执行恢复就正常。一直到实时同步正常 延迟3分钟内他不会提示了

是不是应用也在写数据,同步程序也在同步数据啊?

1 个赞

不会。目标端的库。只有查询代码连接,如果目标端有应用写数据。那肯定会挂。而且已经五六年了。

把binlog文件转换成文本的。

mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin.000095 >binlog.sql

仔细检查一下,因为冲突的是同一个id,应该在日志里面是比较好找的。

在mysql那边查?mysql那边这个主键id可以查到。目标端tidb查是查不到的。执行恢复命令。这个主键id就同步过去了。tidb可以查到。

tidb 的表结构看下呢

一样的,不只是一个表,多个表提示,但是执行恢复命令都正常了