mysql同步到tidb一次在线DDL的时候。因为tidb已经提前加过了索引,跳过错误,或者(之前测试)他会自动跳过。但是这个任务他手动执行跳过之后频繁报错主键冲突,但实际上没有冲突,手动resume-task 恢复他就正常同步了。到那时过十几分钟工半小时他就会又提示冲突
手动resume的时候,确认一下binlog位置是不是回退了,有可能是回退之后,重新同步到问题点重复触发了相同的报错现象。
另外可以新起一个同步任务,同步到下游没有提前创建主键的表,看看是不是这个原因导致的问题。
https://docs.pingcap.com/zh/tidb/stable/dm-safe-mode#dm-安全模式
DM 从 checkpoint 恢复数据同步任务后,可能重复执行某些 binlog 事件而导致下述问题:
- 在进行增量同步过程中,执行 DML 的操作和写 checkpoint 的操作并不是同步的;写 checkpoint 的操作和写下游数据的操作也并不能保证原子性。因此,当 DM 异常退出时,checkpoint 可能只记录到退出时刻之前的一个恢复点。
- 当 DM 重启同步任务,并从 checkpoint 重新开始增量数据同步时,checkpoint 之后的部分数据可能已经在异常退出前被处理过了,从而导致部分 SQL 语句重复执行。
- 如果重复执行
INSERT
操作,会导致主键或唯一索引冲突,引发同步中断;如果重复执行UPDATE
操作,会导致不能根据筛选条件找到之前对应的更新记录。
这个问题在安全模式这段里面有所论述。
安全模式可以解决这个问题。
而且安全模式有自动开启的机制
当 DM 从 checkpoint 恢复增量同步任务(例如 worker 重启,网络中断重连等)时,会自动开启一段时间的安全模式。
我推测你每次resume之后又好了,可能就是这个自动开启的安全模式短时间自动改写了冲突的sql。运行一段时间安全模式退出,然后碰上下一个冲突的sql,就又报错停下了。
大概率是这个问题,建议用sync-diff工具对比一下报错的表,看一下上下游数据是否一致
他是一直在同步。同步到1个点,然后提示冲突,但是冲突的数据在tidb查是没有的。然后手动resume,他继续同步,根据同步的进度感觉是回退了。然后同步十几分钟之后。他就又会出现相同问题,还要继续手动resume,除非实时同步了。他才不会出问题。如果有操作大事务延迟了。他再追日志的时候就会频繁报这个错误
这个是增量同步的过滤delte,目标tidb要全量数据,源端只有近几个月的数据,这个已经是新启的一个任务了
会不会是冲突的数据在一个事务里,然后事务失败了就都回滚了?
然后这可能就是在一个事务内也会冲突的原因了。可能是开启了一个大事务,对一条数据插入->删除->再插入。因为你过滤掉了delete事件,那么在下游就会出现同一个事务中的数据被插入2次。
这么看最好的解决方案也只能是dm开启安全模式。sync-diff因为上下游的表数据本来也不同步,所以也没有办法对比一致性。
对比一下数据
上游不可能人工删除数据的。这些都是属于订单数据,而且他不是一直都冲突,只有在延迟1小时以上。开始追的时候才10十几分钟提示一个冲突,然后点击恢复,就直接继续同步没有这个错误了。
因为春节期间我在订单库有加索引和其他大事务操作。所以有两三次他延迟几个小时的,只要延迟几个小时,他就会提示有主键冲突,但是只要延迟在3分钟内。也就是实时同步正常了。他就不会出现这个问题。
现在几乎没有大事务操作。所以目前实时同步中,不会出现问题了。
就是想了解下问什么会有这个问题,冲突他提示的sql是一个insert,而且他不会是同一个事务有大量insert。
而且也不会在一个事务里面isnert然后删除在insert。他是订单数据库几乎不可能有业务删除,他是停车场进出场的数据,只有insert和update。
是多个源吗?
只有一个
mysql ddl 是直接执行的还是用工具执行的
这个ddl是使用gh-ost执行的。我有添加在线ddl参数,还添加了过滤create index的参数。但是gh-ost是内部生成转换的create index 所以他还是会执行。所以报错。我执行跳过。这个错误,没有问题。开始同步。不过他会频繁提示主键冲突,执行恢复就正常。一直到实时同步正常 延迟3分钟内他不会提示了
是不是应用也在写数据,同步程序也在同步数据啊?
不会。目标端的库。只有查询代码连接,如果目标端有应用写数据。那肯定会挂。而且已经五六年了。
把binlog文件转换成文本的。
mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin.000095 >binlog.sql
仔细检查一下,因为冲突的是同一个id,应该在日志里面是比较好找的。
在mysql那边查?mysql那边这个主键id可以查到。目标端tidb查是查不到的。执行恢复命令。这个主键id就同步过去了。tidb可以查到。
tidb 的表结构看下呢
一样的,不只是一个表,多个表提示,但是执行恢复命令都正常了