关于 TiCDC `old_valuie` + `safe-mode=false` 模式下出现 `Duplicate entry` 的问题

架构情况:

3 tidb + 3 tikv + 3 pd +1 ticdc

上游 tidb v5.0.2
下游 mysql 5.7.25

cdc 任务创建语句:

tiup ctl:v5.0.2 cdc changefeed update --pd=http://XXX:2379 --sink-uri="mysql://user:password@172.26.55.21:3306/?time-zone=&safe-mode=false" --changefeed-id="dev-task6"

cdc 同步报错:

日志报错:

找到 region_id 信息:

上游 tidb 查询这条数据:

下游 mysql 查询这条数据:

下游 MySQL 其实没有数据,为什么还有报重复键的错。

这个情况已经出现几次了,这次把相关信息都贴上来了,如果还需要其他信息,我这边再提供下。麻烦大佬帮忙看下,谢谢!

2 个赞

请问下 这里使用 safe-mode=false 是基于什么需求?当前不建议设置 safe-mode=false

1 个赞

主要是因为我们有很多应用在用canal,需要去下游 mysql 取 binlog。不指定 safe_mode=false 会导致 sql 逻辑发生变化,这样 canal 取到的 binlog 会和上游不一致。

TiCDC 现在有 experimental feature 可以直接输出 canal 格式到 kafka, 您可以评估一下能否解决您的问题。

1 个赞

不行,下游 mysql 除了让 canal 取 binlog 外,还需要承担刷数据的任务。

是这样的,我们 canal 取完 binlog 后,会投递到 rocketmq ,然后处理后存入其他异构数据库,有时候异构数据库的数据需要重新加载,我们会去下游 mysql 里刷新数据,这样数据通过 canal 重新流入异构数据库,而且不会影响到上游 tidb。

咱们是想知道 报主键冲突错误的原因是吧,麻烦把 cdc 版本及配置告诉一下

版本:

配置:


这个 cdc 任务中断比较久了。。

1、cdc 中断这么久,估计只能重新搭建了
2、能否提供一下下游 mysql 这个表的表结构

之前同步了好多次,每次报重复键的表都不一样的。

我重新 dumpling + myloader 搭下数据库,再开个新的 cdc 任务,这次把情况同步给你们把。

可以先给我一下 表结构(可以脱敏,我主要想看索引情况),其实排查咱们这个问题,主要从 1、具体执行的 SQL 语句(批量/或不同语句类型,都是关注的因素)2、锁相关。所以我想看表结构(如果可以的话,可以通过 下游 mysql 日志,找一下相关SQL语句)

1. 表结构:

CREATE TABLE gw_trans_content (
id int(11) unsigned NOT NULL AUTO_INCREMENT,
order_id varchar(32) COLLATE utf8_bin DEFAULT NULL ,
channel_system_id varchar(32) COLLATE utf8_bin NOT NULL,
exchange_type_id varchar(10) COLLATE utf8_bin NOT NULL,
msg_type varchar(10) COLLATE utf8_bin DEFAULT NULL ,
extend_id varchar(32) COLLATE utf8_bin NOT NULL,
class_name varchar(200) COLLATE utf8_bin DEFAULT NULL ,
trans_content mediumtext COLLATE utf8_bin ,
trans_content1 mediumtext COLLATE utf8_bin ,
latest_status varchar(6) COLLATE utf8_bin DEFAULT NULL ,
return_content varchar(4000) COLLATE utf8_bin DEFAULT NULL
return_content1 varchar(4000) COLLATE utf8_bin DEFAULT NULL ,
rsp_code varchar(12) COLLATE utf8_bin DEFAULT NULL,
rsp_msg varchar(200) COLLATE utf8_bin DEFAULT NULL,
memo varchar(500) COLLATE utf8_bin DEFAULT NULL ,
create_time datetime NOT NULL ,
modified_time datetime DEFAULT NULL,
query_time datetime DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uniq_gw_trans_content_1 (extend_id,channel_system_id,exchange_type_id),
KEY idx_gw_trans_content_1 (create_time),
KEY idx_gw_trans_content_2 (order_id),
KEY idx_gw_trans_status_create_time (create_time),
KEY idx_gw_trans_status_oidsn (order_id)
) ENGINE=InnoDB AUTO_INCREMENT=12540448 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

2. 相关 sql

因为下游mysql,没有同步到这条数据,所以没有相关的 binlog。但是在查看下游 mysql binlog 的时候,发现了比较奇怪的现象。

上游 tidb 我们业务代码实现的是:

begin -> insert into t (id) value (1) -> commit
begin -> update t set where id =1 -> commit

下游 binlog 输出的是:

begin -> insert into t (id) value (1) -> update t set where id =1 -> commit

检查过代码,没有把 insert 和 update 放在一个事务里的逻辑。

2 的问题,可以忽略,cdc 是最终一致性(不会影响数据准确性的)

问一下,下游 mysql 方便开启 general log 吗(可以在报错时,开启一小段时间,想看看具体的 SQL 语句,不然不太好排查)

general log 打开了,刚刚报重复键错误了,这边排查的话需要哪些信息,我一起发给你

1、下游表无此主键对应的数据
2、mysql 报错时的日志(general log 会有记录)

我确认下这个数据怎么定位的,是去 cdc log 找到这条报错,然后网上找最近的一个 region_id ,然后通过命令 curl http://172.26.xxx.xxx:10080/regions/$region_id ,去定位吗?

看mysql 的,不是tidb 的(主键冲突发生在下游 mysql 吧)

@HHHHHHULK 我看你给的 日志中,并没有报错啊(开启完 mysql general log 之后,需要再启动一下 cdc,让他报主键冲突报错)(其实我想抓到 下游报错的 具体 SQL,所以需要在报主键冲突错误之前,就开启 general log)

general log 昨天就开了,文件太大,我把前面没用的都截掉了

:joy:,奇怪的是我没有找到报错相关的信息啊(grep -i error log 没有发现有报错啊,1062 错误代码也没有啊)