从模拟数据到场景复现,剖析 MySQL Online DDL 异常报错之谜

云掣YunChe8个月前最新动态462

本文从模拟数据到场景复现,深入浅出的分享了 MySQL 在线 DDL 变更误触报错的原因分析和解决方案,以减少或避免在Online DDL操作中误触发异常错误,提高数据库变更的成功率,希望能对遇到相似问题的客户起到一定的帮助。云掣专注于可观测运维,为您的数字化转型保驾护航~

前言

业务执行一条 alter table table_name engine=innodb 失败了很多次,一直无法执行成功,报错 ERROR 1062 (23000): Duplicate entry xxx for key 'xxx',在官方文档中也提到过,Online DDL 期间可能会出现 ERROR 1062 (23000): Duplicate entry 异常,但是没有详细说明,什么情况下会触发。业务执行 DDL 的时候,一直没有成功,意味着距离找到答案不远了。

When running an in-place online DDL operation, the thread that runs the ALTER TABLE statement applies an online log of DML operations that were run concurrently on the same table from other connection threads. When the DML operations are applied, it is possible to encounter a duplicate key entry error (ERROR 1062 (23000): Duplicate entry), even if the duplicate entry is only temporary and would be reverted by a later entry in the online log. This is similar to the idea of a foreign key constraint check in InnoDB in which constraints must hold during a transaction.

https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-limitations.html

1. 模拟现场

1.1 测试表结构

CREATE TABLE `ddl_test` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NOT NULL,
  `channel_id` tinyint(4) NOT NULL,
  `version` bigint(20) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `user_info` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unq_index` (`user_id`,`channel_id`,`version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


1.2 制造测试数据

mysql_random_data_load 是使用 Go 语言开发的 MySQL 随机造数工具,可从下方链接中直接下载编译完成的二进制程序。

下载地址:mysql_random_data_load GitHub

08a7c9c1106c664cf3dfc5e3f14c1182.png

下载对应系统版本的文件,开箱即用。

# 解压后会得到一个二进制程序
tar -zxvf mysql_random_data_load_0.1.12_Linux_x86_64.tar.gz
# 验证
./mysql_random_data_load --help


造数命令模版:

mysql_random_data_load -h127.0.0.1 -u'用户' -p'密码' --max-threads=线程数 库名 表名 造数多少行

造数工具准备好了,现在需要制造一些测试数据,便于观测现象。

mysql_random_data_load -h127.0.0.1 -u'test' -p --max-threads=10 test ddl_test 2000000

1.3 场景复现

截图_20250114173810.png

让人疑惑的是,Session 1 第二次写入并没有成功,为什么会导致 DDL 执行失败呢?

2. 原因分析

经过源码分析,发现 MySQL Online DDL 期间所有的写入都会记录到增利日志中,增量日志是通过聚簇索引(主键)来校验唯一性,只要主键不冲突后就直接写入到增量日志中,然后再依次写唯一索引、二级索引。

image.png

此时唯一索引由于违反约束,执行失败,抛出异常,增量日志这里也没有进行回滚,造成在 Online DDL 合并阶段,违反唯一索引的记录会被合并到表里,造成 DDL 执行失败。

image (1).png

3. 如何解决

了解到业务是一个并发写入的场景,会偶发导致重复写入的问题,定位到业务场景后,通过降低了并发,减少了重复写入。最后 DDL 执行成功。如果遇到该问题,建议先定位问题是由于哪些 SQL 造成的,然后和业务侧配合规避掉这个异常。

4. 误导报错

经过测试在 MySQL 5.7.17 版本复现该问题的时候,会出现一个误导报错。虽然是由 unq_index 约束造成的,在 DDL 会话里面,会直接报错主键的值,并且这个自增主键值不存在,因为已经被回滚了,回滚后自增主键不会重新分配了,会让用户一头雾水。

root@mysql  [deom]>alter table ddl_test engine=innodb, ALGORITHM=INPLACE, LOCK=NONE;
ERROR 1062 (23000): Duplicate entry '200006' for key 'PRIMARY'

后记

经过测试,该问题在最新的长期支持版本 MySQL 8.4 中依然存在。

云掣专注于可观测运维,致力解决企业上云难、用云难、管云难三大问题。基于云数据库提供7*24小时保障服务,提供开发支持、数据库体系规范、持续优化、数据库架构支持,保障企业数据库高效稳定运行。全面提升企业的运维效率和稳定性,助力企业完成云时代的数字化转型,满足客户在数据库管理和云迁移方面的多样化需求!



相关文章

正式发布 | 《云运维服务白皮书》开放下载!

正式发布 | 《云运维服务白皮书》开放下载!

在全球数字化变革的背景下,为适应数字经济环境下企业生存发展和市场变化的需要,企业进行主动的、系统性、整体性的数字化转型升级。大数据、云计算、人工智能、区块链等新一代信息通信技术为企业的数字化转型提供了...

ACOS可观测运维套件—容器监控

ACOS可观测运维套件—容器监控

一、简介ACOS统一运维监控平台最新4.0版本支持容器能力,对于容器数据采集成功后会上报到控制台「容器监控」,您可以查看到租户内容器各种对象的数据信息。容器数据有两种查看和分析模式,通过切换页面左上角...

深度解读|云掣《云运维服务白皮书》全方位解析!

深度解读|云掣《云运维服务白皮书》全方位解析!

如今全球各行各业纷纷进行数字化变革,为适应数字经济环境下企业生存发展和市场变化的需要,企业选择进行主动的、系统性、整体性的数字化转型升级。大数据、云计算、人工智能、区块链等新一代信息通信技术为企业的数...

阿里云再度携手袋鼠云,重磅联合发布ACOS统一运维监控平台

阿里云再度携手袋鼠云,重磅联合发布ACOS统一运维监控平台

1月13日,袋鼠云旗下数据化运维子公司云掣科技与阿里云再度签署战略合作协议,阿里云智能云原生应用平台负责人丁宇(花名:叔同)、阿里云云原生PaaS负责人张军(花名:游骥)、阿里云智能云原生可观测负责人...

初识MySQL数据库

初识MySQL数据库

数据库首先提问,按照常理来说,什么是数据库呢?不少人想到的一点就是,不就是数据的集合吗?是的,数据库从数据存储方面确实只是数据的集合,但是数据库不只是为了集合数据而存在。如果是为了集合数据,像我们磁盘...

袋鼠云CEO宁海元:打通数智基建到应用的通路,让数据不再“躺灰” | 数据猿专访

袋鼠云CEO宁海元:打通数智基建到应用的通路,让数据不再“躺灰” | 数据猿专访

一家大型制造企业的老板最近心情颇为复杂。几年前,企业投入巨资构建数据存储和治理系统,如今数据确实源源不断地积累,但他发现,这些数据似乎并没有带来预期的业务收益。虽然存储成本逐年攀升,但数据依旧沉睡在系...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。