TiDB3.10,mysql作为drainer的下游,出现1062错误。

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

【概述】 TiDB3.10,mysql作为drainer的下游,出现1062错误。

【备份和数据迁移策略逻辑】

【背景】 正常地部署了3 pump 1 drainer 和下游mysql, sqlmode一致

【现象】 drainer 出现 1062 错误 (重复的唯一键)

【问题】 发现,无论是部署drainer或者是使用mydumper数据到mysql去恢复,都会遇到重复键报错。

【业务影响】

【TiDB 版本】 3.10

【附件】


若提问为性能优化、故障排查类问题,请下载脚本运行。终端输出的打印结果,请务必全选并复制粘贴上传。

1 个赞

补充: 重复键的情况是分布在不同的表的,初步观察没什么特征。

为什么使用 3.1 版本呀 ? 3.1 我们不推荐哈,算是一个过渡版本。如果可以的话还是建议使用 4.0.x 或者 5.0.x 版本,或者是 3.0.x

排查思路:如果是使用 mydumper 数据到 mysql 恢复也报错主键冲突。那么可以确认下 mydumper 导出的文件 grep 一下是否有冲突的数据。如果没有,看下下游 mysql 是否已经存在该行数据了。

我查看了mydumper出来的数据,是存在重复键,内容不一样的两条数据。

这是导入到mysql时的报错:

** (myloader:32019): CRITICAL **: 12:46:21.958: Error restoring datacenter_special.news_base from file datacenter_special.news_base.
sql.gz: Duplicate entry 'http://XXXX' for key 'unified_key2'

这是导出来的数据:

zgrep 'http://XXXX' datacenter_special.news_base.sql.gz


(4212405,'2020-10-30 20:22:40','巨潮快讯','快讯','http://XXXX','1060',744743,NULL,NULL,'业富联:前三季度净利润88亿元  同比下降13.54%',NULL,0,1,'2020-10-30 20:23:29','2020-10-30 20:26:35','2020-10-30 20:26:35'),
(4238390,'2020-10-30 20:20:32','巨潮快讯','快讯','http://XXXX','1060',744769,NULL,NULL,'业富联:前三季净利88亿元  同比下降13.54%',NULL,0,1,'2020-10-30 20:23:29','2020-10-30 20:23:35','2020-10-30 20:23:35'),

而目前查询TiDB,这两条数据是同时存在的。通过id查询能查到数据,通过Website查询则查不到。

mysql> SELECT * FROM news_base WHERE Website = (SELECT Website FROM news_base WHERE id = 4238390);
Empty set

mysql> SELECT id FROM news_base WHERE id = 4238390;
+---------+
| id      |
+---------+
| 4238390 |
+---------+
1 row in set (0.01 sec)
 

我感觉是虽然设置了unique key,但是tidb允许了两条重复键的数据插入。我想确认的是,当前情况下去升级到4的话,会不会有问题?

应该是碰到了低版本的 bug,可以搜索下 astug 也有其他用户遇到过。使用 admin check table 看下

那我现在可以如何处理?两个问题:

  1. 已经出问题的表可如何使之唯一索引重新生效。

  2. 我现在通过drainer同步数据到mysql,如何可以使得drainer跳过1062错误?

1 个赞

上述命令执行下,确认是否是 数据索引不一致导致的问题。

drainer 报错主键冲突,只能有一条记录写入到下游才对。所以你这边可以选择删除已写入的数据。重启 drainer 。或者 直接重启 drainer,重启的前几分钟会开启 safe-mode,replace into 的方式覆盖写入。

mysql> admin check table news_base;
8003 - news_base err:[admin:1]index:<nil> != record:&admin.RecordData{Handle:1127840, Values:[]types.Datum{types.Datum{k:0x6, collation:0x0, decimal:0x0, length:0x0, i:0, b:[]uint8{0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x63, 0x6e, 0x69, 0x6e, 0x66, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6e, 0x2f, 0x6e, 0x65, 0x77, 0x2f, 0x64, 0x69, 0x73, 0x63, 0x6c, 0x6f, 0x73, 0x75, 0x72, 0x65, 0x2f, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x3f, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x3d, 0x73, 0x7a, 0x73, 0

重启 drainer 。或者 直接重启 drainer,重启的前几分钟会开启 safe-mode,replace into 的方式覆盖写入。

关于这个,因为这样的数据很多,我已经重启了几次,都还没完全消除。

参考这里,我先把safe-mode在配置文件上启动了。

1.麻烦确认下上游是否是使用 INSERT ON DUPLICATE 方式插入的数据,这边有个已知 bug
触发条件是:
触发条件如下:

  1. 非 autocommit=1 的事务。(即使用 begin/commit 或者 autocommit=0,autocommit=1 来提交的事务)
  2. 使用 insert on duplicate key update 语句
  • 单条 insert 语句内写入多行重复数据,且重复数据在写入前在表中不存在
  • 且多行数据中有唯一索引冲突,且冲突的数据是之前不存在的

如果是可以看下这个帖子 on duplicate key update 主键重复问题

safe-mode 参数生效问题可以从日志中确认参数。

那我现在该如何修复此数据?

  1. 导出表数据进行备份。

备份时注意通过表数据来备份,因为索引是存在缺失的,表数据是完整的。最简单的方式是直接 select * from t。

  1. 恢复缺失的索引,执行

admin recover index [table_name] [index_name];

对于相同唯一索引列的数据,因为打破了唯一约束,无法自动补齐。

  1. 执行如下 SQL 得到所有没有成功恢复的唯一索引的数据

select *, _tidb_rowid from [table_name] where _tidb_rowid not in
(select _tidb_rowid from [table_name] use index ([index_name]));

  1. 导出所有重复行数据,再用 _tidb_rowid 将重复行数据删除,
  2. 用户根据实际业务场景,对重复行的数据进行处理后再重新导入数据库。

解决办法如上。还是建议升级。避免再次遇到问题。

1 个赞

了解,看在这么多字并且条理清晰的份上,给你一个小心心。

:yum::yum::yum:

此话题已在最后回复的 1 分钟后被自动关闭。不再允许新回复。