INSERT UPDATE导致MySQL Crash的场景解惑

2024年 5月 2日 70.1k 0

技术社群的这篇文章《故障分析 | 一则 INSERT UPDATE 触发 MySQL Crash 的案例》给出一个和SQL语句执行相关的场景,问题排查过程包括了如何找到官方bug,很实用,值得学习参考。

1故障现象

某个业务 MySQL 实例(MySQL 5.7.20 社区版)发生 Crash,现需要对其具体原因进行分析。

/mysql/mysql-5.7.20/bin/mysqld(my_print_stacktrace+0x35)[0xf468f5]
/mysql/mysql-5.7.20/bin/mysqld(handle_fatal_signal+0x4a4)[0x7cd434]
/lib64/libpthread.so.0(+0xf100)[0x7f3564112100]
/mysql/mysql-5.7.20/bin/mysqld(_ZN10Field_blob15copy_blob_valueEP11st_mem_root+0x30)[0x7fd160]
/mysql/mysql-5.7.20/bin/mysqld(_Z25mysql_prepare_blob_valuesP3THDR4List14ItemEP11st_mem_root+0x29e)[0xe9901e]
/mysql/mysql-5.7.20/bin/mysqld(_Z12write_recordP3THDP5TABLEP9COPY_INFOS4_+0x212)[0xe995f2]
/mysql/mysql-5.7.20/bin/mysqld(_ZN14Sql_cmd_insert12mysql_insertEP3THDP10TABLE_LIST+0x812)[0xe9a982]
/mysql/mysql-5.7.20/bin/mysqld(_ZN14Sql_cmd_insert7executeEP3THD+0xce)[0xe9b15e]
/mysql/mysql-5.7.20/bin/mysqld(_Z21mysql_execute_commandP3THDb+0xd82)[0xd13b62]
/mysql/mysql-5.7.20/bin/mysqld(_Z11mysql_parseP3THD12Parser_state+0x3a5)[0xd18205]
/mysql/mysql-5.7.20/bin/mysqld(_Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command+0x11bf)[0xd1942f]

2故障分析

根据堆栈打印的信息可以得知,当时 Crash 的时间点 MySQL 正在执行 INSERT 操作,且操作涉及 BLOB 数据类型的数据,在源码执行到 copy_blob_value
 函数时触发 Crash。

可在本地测试环境中安装同版本 MySQL 实例后,使用 gdb 定位代码具体位置。

gdb ./mysqld
(gdb) b *0x7fd160
Breakpoint 1 at 0x7fd160: file /export/home/pb2/build/sh_0-32013917-1545390211.74/mysql-5.7.25/sql/field.cc, line 3053.

在 https://github.com/mysql/mysql-server/blob/mysql-5.7.25/sql/field.cc
 中找到对应行数的源码,在该代码附近没有 BUG 修复记录。

ctrl+f
 搜索函数 copy_blob_value
,然后点击左边的 ...
,之后选择 View git blame
,发现有一个 BUG 修复记录。

根据该 BUG 修复记录描述,MySQL 在执行 INSERT ... UPDATE
 类型语句时(也就是  INSERT ... ON DUPLICATE
 ),当 INSERT
 操作失败之后(Unique Key 冲突),会执行 UPDATE
 操作,而 UPDATE
 操作会在 INSERT
 的 VALUE()
 中找到需要更新的 Old Data。整个流程如下,

  1. 保存 INSERT
     中的数据或 UPDATE
     后的新数据。
  2. INSERT
     失败,进入 UPDATE
     流程,找到旧数据。
  3. COPY 旧数据。

可以看到在找到 Old Data 后,新的指针就会指向这个 Data 内存地址,这时 2 个指针同时指向一个内存地址,此处存在 3 种导致 Crash 的情况,

  1. valgrind error:指针 LHS_FIELD
     指向的内存已被释放并重新分配以容纳新数据,将导致空指针问题。
  2. Update Bad Data:指针 LHS_FIELD->ptr
     指向的内存未被释放但被重用,并且新数据可以放在相同的内存位置,则更新错误的值。
  3. Both:如果新内存分配在与前一个内存相同的位置,则上述两种情况都可能发生。

BUG 链接

https://bugs.mysql.com/bug.php?id=79243

3触发条件

使用 INSERT ... ON DUPLICATE
 语句操作 BLOB 数据类型的列。

4处理方法

  • MySQL 5.7.22 修复了该 BUG,可以进行升级。
  • 不使用 INSERT ... ON DUPLICATE
     语句操作 BLOB 数据类型的列。

如果您认为这篇文章有些帮助,还请不吝点下文章末尾的"点赞"和"在看",或者直接转发朋友圈,

近期更新的文章:《MySQL大表增加唯一索引场景》《Windows的匿名登录》
《TCP出现缓存超负荷导致MySQL连接中断场景》
《自动化运维的安全与合规性》
《标准的类型都有什么?》
近期的热文:《推荐一篇Oracle RAC Cache Fusion的经典论文》
《"红警"游戏开源代码带给我们的震撼》
文章分类和索引:《公众号1400篇文章分类和索引》

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论