mysql 8.0崩溃时error.log不提供真实代码行号,仅含断言触发点;必须结合core dump、带调试符号的二进制、log_error_verbosity=3及gdb解析才能定位源码行。

MySQL 8.0 Crash时错误日志里根本没代码行号?
MySQL 8.0 默认错误日志(error.log)只记录崩溃前的堆栈摘要,比如 mysqld: mysys/my_thread.cc:79: void my_thread_exit(int): Assertion `!thd || thd->killed' failed. 这类信息看似有文件和行号,但实际是断言触发点,不是真正出问题的业务逻辑位置。真正导致崩溃的代码往往在上层数十帧之外,必须结合 core dump 和调试符号才能定位。
必须开启 symbolic stack trace + core dump 才能回溯到源码行
仅靠 error.log 日志无法定位具体代码行——它不包含完整调用链,也不带符号信息。你需要让 MySQL 在崩溃时生成可调试的上下文:
- 启动前确保
core-file已启用:mysqld --core-file,并确认系统允许生成 core:ulimit -c unlimited - 使用带调试符号的二进制:官方 RPM/DEB 包默认不含 debuginfo;需额外安装
mysql-community-debuginfo(RHEL/CentOS)或mysql-server-dbgsym(Ubuntu) - 配置
log_error_verbosity = 3(非默认),否则堆栈可能被截断,丢失关键帧 - 崩溃后检查
error.log中是否出现类似Attempting backtrace和stack_bottom = ... thread_stack = ...的段落——这是符号化堆栈可用的前提
用 gdb 解析 core 文件时的关键命令顺序
拿到 core 和匹配的 mysqld 二进制后,gdb 是唯一可靠手段。注意顺序错一步就看不到源码行:
- 先加载二进制:
gdb /usr/sbin/mysqld core.12345 - 立即执行
set debug-file-directory /usr/lib/debug(路径依 debuginfo 安装位置而定) - 运行
bt full查看完整堆栈;若看到?? (),说明符号未加载成功 - 关键技巧:对疑似问题帧(如
ha_innobase::update_row)执行frame 12再list,gdb 才会尝试显示对应源码行(需源码在本地或已配置directory) - 若无源码,至少用
info registers+x/10i $pc查看汇编指令,配合 MySQL 源码中函数签名反推逻辑位置
常见陷阱:日志里“Assertion failed”不是根因
错误日志中高频出现的 Assertion `xxx' failed 往往是防御性检查,真正问题早在此前就发生了——比如内存越界破坏了后续结构体字段,几轮函数调用后才在断言处暴露。此时堆栈顶部的函数只是“发现者”,不是“肇事者”:
- 不要只盯着断言那一行;用
bt往上翻 5–10 帧,重点关注涉及用户 SQL、存储引擎接口(ha_*)、事务状态变更(trans_*)的调用点 - 如果堆栈里反复出现
my_malloc、ut_allocator或mem_heap_create,优先怀疑内存管理异常,检查是否启用了--innodb-use-native-aio=OFF(Linux aio bug 曾引发类似崩溃) - 线上环境若无法保留 core,至少启用
log_error_services = 'log_filter_internal; log_sink_syseventlog; log_sink_json'并配合log_error_suppression_list过滤噪音,让真正异常堆栈不被淹没
能从 error.log 直接读出代码行号的情况极少,几乎只存在于你本地编译且未 strip 的调试版 MySQL 中。生产环境必须依赖 core + debuginfo + gdb 的组合,而且每一步的环境一致性(版本、build flags、debuginfo 匹配度)都卡得极死——少一个条件,list 就永远显示不出那行源码。











