終止分區表變更操作時誤刪數據字典緩存導致MySQL崩潰分析

終止分區表變更操作時誤刪數據字典緩存導致MySQL崩潰分析

1. 問題簡述

在 MySQL 中,當終止一個處于 committing alter table to storage engine 階段的分區表操作時,InnoDB 會嘗試進行回滾并清理數據字典緩存。不幸的是,過程中發生了誤刪表緩存對象的情況 —— InnoDB 錯誤地移除了另一張非目標表的緩存條目,導致引用計數不為 0,觸發斷言失敗并導致 MySQL 崩潰。

2. 復現步驟

環境說明:

系統:CentOS 7

數據庫:MySQL 8.0.32

2.1 建表準備

CREATE DATABASE TEST;
CREATE TABLE TEST.A ( X INT)
PARTITION BY RANGE (X) (PARTITION P0 VALUES LESS THAN (10000),PARTITION PMAX VALUES LESS THAN MAXVALUE
);
CREATE TABLE TEST.A_1 LIKE TEST.A;
SELECT COUNT(*) FROM TEST.A_1;

2.2 反復嘗試終止 ALTER TABLE 操作

在一個 Shell 中持續執行終止 "committing alter table to storage engine" 狀態(KILL相應SQL請求)的線程:

while true; do  {   mysql --login-path=mylogin -BNe  'SELECT CONCAT("KILL ",ID ,";") FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = "COMMITTING ALTER TABLE TO STORAGE ENGINE";' | mysql --login-path=mylogin  -vvv ; } ; done

2.3 循環執行 ALTER 操作

在另一個 Shell 中循環執行添加與刪除分區的操作:

while true; do  {   mysql --login-path=mylogin -BNe  "ALTER TABLE test.a ADD PARTITION (PARTITION pmax VALUES LESS THAN MAXVALUE);" ;   mysql --login-path=mylogin -BNe " ALTER TABLE test.a DROP PARTITION pmax;" ; }; done

3. 崩潰日志與原因分析

DROP PARTITION 操作在關鍵階段被 KILL 時,崩潰發生:

2025-06-05T17:03:19.270698+08:00 2975 [ERROR] [MY-013183] [InnoDB] Assertion failure: dict0dict.cc:1885:table->get_ref_count() == 0 thread 140327459395328
InnoDB: We intentionally generate a memory trap.
InnoDB: Submit a detailed bug report to http://bugs.mysql.com.
InnoDB: If you get repeated assertion failures or crashes, even
InnoDB: immediately after the mysqld startup, there may be
InnoDB: corruption in the InnoDB tablespace. Please refer to
InnoDB: http://dev.mysql.com/doc/refman/8.0/en/forcing-innodb-recovery.html
InnoDB: about forcing recovery.
2025-06-05T09:03:19Z UTC - mysqld got signal 6 ;
Most likely, you have hit a bug, but this error can also be caused by malfunctioning hardware.
BuildID[sha1]=7afc1fad28c808c287fa7599451d3355e1b3be73
Thread pointer: 0x7fa054000f40
Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong...
stack_bottom = 7fa0885e8a30 thread_stack 0x100000
/usr/local/mysql-debug/bin/mysqld(my_print_stacktrace(unsigned char const*, unsigned long)+0x43) [0x48da47f]
/usr/local/mysql-debug/bin/mysqld(print_fatal_signal(int)+0x3a2) [0x34cf2af]
/usr/local/mysql-debug/bin/mysqld(my_server_abort()+0x6b) [0x34cf561]
/usr/local/mysql-debug/bin/mysqld(my_abort()+0xd) [0x48d0eaf]
/usr/local/mysql-debug/bin/mysqld(ut_dbg_assertion_failed(char const*, char const*, unsigned long)+0x1d1) [0x4d9b051]
/usr/local/mysql-debug/bin/mysqld() [0x4f15f0b]
/usr/local/mysql-debug/bin/mysqld(dict_table_remove_from_cache(dict_table_t*)+0x1d) [0x4f166cd]
/usr/local/mysql-debug/bin/mysqld(dict_partitioned_table_remove_from_cache(char const*)+0x159) [0x4f16829]
/usr/local/mysql-debug/bin/mysqld() [0x4a07dc2]
/usr/local/mysql-debug/bin/mysqld() [0x337ee49]
/usr/local/mysql-debug/bin/mysqld(mysql_alter_table(THD*, char const*, char const*, HA_CREATE_INFO*, Table_ref*, Alter_info*)+0x3bf6) [0x338a12a]
/usr/local/mysql-debug/bin/mysqld(Sql_cmd_alter_table::execute(THD*)+0x5d4) [0x39af486]
/usr/local/mysql-debug/bin/mysqld(mysql_execute_command(THD*, bool)+0x54c8) [0x32a5677]
/usr/local/mysql-debug/bin/mysqld(dispatch_sql_command(THD*, Parser_state*)+0x756) [0x32a785f]
/usr/local/mysql-debug/bin/mysqld(dispatch_command(THD*, COM_DATA const*, enum_server_command)+0x15a8) [0x329d7c3]
/usr/local/mysql-debug/bin/mysqld(do_command(THD*)+0x5bd) [0x329b853]
/usr/local/mysql-debug/bin/mysqld() [0x34ba2df]
/usr/local/mysql-debug/bin/mysqld() [0x51ed236]
/lib64/libpthread.so.0(+0x7ea5) [0x7fa13cf41ea5]
/lib64/libc.so.6(clone+0x6d) [0x7fa13b55bb0d]Trying to get some variables.
Some pointers may be invalid and cause the dump to abort.
Query (7fa054010390): ALTER TABLE test.a DROP PARTITION pmax
Connection ID (thread ID): 2975
Status: KILL_CONNECTION
堆棧信息
(gdb) bt
#0  0x00007fa13cf46aa1 in pthread_kill () from /lib64/libpthread.so.0
#1  0x00000000048da549 in my_write_core (sig=6) at /software/db/mysql-8.0.32/mysys/stacktrace.cc:295
#2  0x00000000034cf4ec in handle_fatal_signal (sig=6) at /software/db/mysql-8.0.32/sql/signal_handler.cc:230
#3  <signal handler called>
#4  0x00007fa13b493387 in raise () from /lib64/libc.so.6
#5  0x00007fa13b494a78 in abort () from /lib64/libc.so.6
#6  0x00000000034cf671 in my_server_abort () at /software/db/mysql-8.0.32/sql/signal_handler.cc:286
#7  0x00000000048d0eaf in my_abort () at /software/db/mysql-8.0.32/mysys/my_init.cc:258
#8  0x0000000004d9b051 in ut_dbg_assertion_failed (expr=0x6d821d3 "table->get_ref_count() == 0", file=0x6d81ab8 "/software/db/mysql-8.0.32/storage/innobase/dict/dict0dict.cc", line=1885) at /software/db/mysql-8.0.32/storage/innobase/ut/ut0dbg.cc:99
#9  0x0000000004f15f0b in dict_table_remove_from_cache_low (table=0x7fa0445c6e08, lru_evict=false)at /software/db/mysql-8.0.32/storage/innobase/dict/dict0dict.cc:1885
#10 0x0000000004f166cd in dict_table_remove_from_cache (table=0x7fa0445c6e08) at /software/db/mysql-8.0.32/storage/innobase/dict/dict0dict.cc:1969
#11 0x0000000004f16829 in dict_partitioned_table_remove_from_cache (name=0x7fa0885e2bd0 "test/a")at /software/db/mysql-8.0.32/storage/innobase/dict/dict0dict.cc:1999
#12 0x0000000004a07dc2 in innobase_dict_cache_reset (schema_name=0x7fa054010868 "test", table_name=0x7fa054010880 "a")at /software/db/mysql-8.0.32/storage/innobase/handler/ha_innodb.cc:3991
#13 0x000000000337ee49 in mysql_inplace_alter_table (thd=0x7fa054000f40, schema=..., new_schema=..., table_def=0x7fa0445af410, altered_table_def=0x7fa054012d60, table_list=0x7fa054011020, table=0x0, altered_table=0x7fa05403e230, ha_alter_info=0x7fa0885e3710, inplace_supported=HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE, alter_ctx=0x7fa0885e4630, columns=std::set with 0 elements, fk_key_info=0x7fa05403b720, fk_key_count=0, fk_invalidator=0x7fa0885e4560) at /software/db/mysql-8.0.32/sql/sql_table.cc:13744
#14 0x000000000338a12a in mysql_alter_table (thd=0x7fa054000f40, new_db=0x7fa054010868 "test", new_name=0x0, create_info=0x7fa0885e6170, table_list=0x7fa054011020, alter_info=0x7fa0885e6000) at /software/db/mysql-8.0.32/sql/sql_table.cc:17405
#15 0x00000000039af486 in Sql_cmd_alter_table::execute (this=0x7fa054011670, thd=0x7fa054000f40) at /software/db/mysql-8.0.32/sql/sql_alter.cc:349
#16 0x00000000032a5677 in mysql_execute_command (thd=0x7fa054000f40, first_level=true) at /software/db/mysql-8.0.32/sql/sql_parse.cc:4688
#17 0x00000000032a785f in dispatch_sql_command (thd=0x7fa054000f40, parser_state=0x7fa0885e7910) at /software/db/mysql-8.0.32/sql/sql_parse.cc:5322
#18 0x000000000329d7c3 in dispatch_command (thd=0x7fa054000f40, com_data=0x7fa0885e8a00, command=COM_QUERY)at /software/db/mysql-8.0.32/sql/sql_parse.cc:2036
#19 0x000000000329b853 in do_command (thd=0x7fa054000f40) at /software/db/mysql-8.0.32/sql/sql_parse.cc:1439
#20 0x00000000034ba2df in handle_connection (arg=0xbe191d0) at /software/db/mysql-8.0.32/sql/conn_handler/connection_handler_per_thread.cc:302
#21 0x00000000051ed236 in pfs_spawn_thread (arg=0xbe23890) at /software/db/mysql-8.0.32/storage/perfschema/pfs.cc:2986
#22 0x00007fa13cf41ea5 in start_thread () from /lib64/libpthread.so.0
#23 0x00007fa13b55bb0d in clone () from /lib64/libc.so.6
崩潰核心棧:
dict_partitioned_table_remove_from_cache-> strncmp("test/a", "test/a_1#p#p0", 6) == 0  // 誤判為匹配-> dict_table_remove_from_cache() 導致 ref_count != 0 觸發斷言
GDB 調試關鍵值:
(gdb) p name
$1 = "test/a"
(gdb) p prev_table->name.m_name
$2 = "test/a_1#p#p0"
(gdb) p strncmp("test/a", "test/a_1#p#p0", 6)
$3 = 0   // 返回0,誤認為匹配

由于 "test/a""test/a_1#p#p0" 的前綴,使用 strncmp(name, m_name, name_len) 判斷時發生誤判,錯誤地將 test.a_1 的分區子表從緩存中移除。

4. 關鍵源碼解讀

崩潰函數在 InnoDB 源碼中的定義如下(文件 dict0dict.cc):

void dict_partitioned_table_remove_from_cache(const char *name) {ut_ad(dict_sys_mutex_own());size_t name_len = strlen(name);for (uint32_t i = 0; i < hash_get_n_cells(dict_sys->table_id_hash); ++i) {dict_table_t *table = static_cast<dict_table_t *>(hash_get_first(dict_sys->table_hash, i));while (table != nullptr) {dict_table_t *prev_table = table;table = static_cast<dict_table_t *>(HASH_GET_NEXT(name_hash, prev_table));if (prev_table->is_dd_table) {continue;}if ((strncmp(name, prev_table->name.m_name, name_len) == 0) &&dict_table_is_partition(prev_table)) {btr_drop_ahi_for_table(prev_table);dict_table_remove_from_cache(prev_table);  // 錯誤刪除}}}
}
核心問題:
  • 使用 strncmp(name, m_name, name_len) 導致前綴匹配誤判為全匹配
  • 應該采用 精確表名匹配,如:
if (strcmp(name, prev_table->name.m_name) == 0)
  • 或使用更嚴格的邏輯,確保僅匹配當前表或其合法分區。

5. 結論與建議

問題根因:
  • 緩存移除邏輯基于前綴匹配,未驗證完整表名,誤刪其他表結構對象;
  • 被刪表正在被引用,引用計數 ref_count ≠ 0,觸發 InnoDB 保護性斷言;
  • 最終導致 MySQL 進程崩潰。
潛在影響:
  • 表結構類似(同名前綴)的表,在 DDL 并發或異常終止場景下可能被誤刪;
  • 可能存在更廣泛的 InnoDB 緩存一致性漏洞,特別在并發和 kill 介入場景中。
建議修復方向:
  • strncmp(name, m_name, name_len) 替換為更安全的 strcmp 或引入完整名判斷;
  • 限制 dict_partitioned_table_remove_from_cache() 中刪除的表名范圍,僅處理嚴格匹配的表;
  • 增強 DDL 異常中斷處理的健壯性,確保引用關系、緩存清理邏輯的一致性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/86574.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/86574.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/86574.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

進程關系與守護進程全解析

進程關系和守護進程 進程組 每一個進程除了有一個進程ID(PID)之外還屬于一個進程組。進程組是一個或者多個進程的集合&#xff0c; 一個進程組可以包含多個進程&#xff0c;每一個進程組也有一個唯一的進程組ID(PGID)&#xff0c; 并且這個PGID 類似于進程ID&#xff0c; 同樣…

PyAutoGUI 測試框架

??親愛的技術愛好者們,熱烈歡迎來到 Kant2048 的博客!我是 Thomas Kant,很開心能在CSDN上與你們相遇~?? 本博客的精華專欄: 【自動化測試】 【測試經驗】 【人工智能】 【Python】

Git安裝避坑指南

Git高速下載 程序員面試資料大全&#xff5c;各種技術書籍等資料-1000G 一、安裝前準備&#xff1a;避免環境沖突 1. 檢查系統殘留&#xff08;Windows&#xff09; # 檢查舊版Git殘留 where git where git.exe# 檢查環境變量 $env:PATH -split ; | Select-String git# 清理…

MATLAB中的并行加速技術與工具

文章目錄 MATLAB中的并行加速技術與工具1. 多線程計算&#xff08;隱式并行&#xff09;2. Parallel Computing Toolbox (并行計算工具箱)2.1 parfor (并行for循環)2.2 spmd (單程序多數據)2.3 parfeval (異步并行執行) 3. GPU計算4. 分布式計算 (MATLAB Parallel Server)5. 批…

GR00T N1.5 技術報告 -- Nvidia -- 2025.6.11 -- 開源

0. 前言 GR00T N1 的詳細介紹 Isaac-GR00T 在6.11 進行了全面升級&#xff0c;從 N1 進化為 N1.5&#xff0c;但基本還是基于之前的架構&#xff0c;官方發布了一個技術報告&#xff0c;并更新了github庫&#xff0c;之前的N1也做了獨立版本 N1 N 1.5 github 技術報告 model…

SRS WebRTC 入門

什么是 SRS WebRTC? SRS (Simple Realtime Server) 是一個支持 WebRTC 流媒體的開源媒體服務器。它允許你建立基于 WebRTC 的低延遲直播和實時通信應用。 快速開始 1. 安裝 SRS bash # 使用 Docker 快速安裝 docker run --rm -it -p 1935:1935 -p 1985:1985 -p 8080:8080…

從手機隨拍到標準掃描件:AI如何智能校正證件照片(Python+OpenCV)

目錄 一、概述二、解決方案2.1 核心挑戰&#xff1a;AI眼中的“三座大山”2.2 設計思路&#xff1a;給AI一個“智能提示”2.3 實現流程&#xff1a;四步搞定 三、代碼實現3.1 依賴庫3.2 代碼 四、結語 一、概述 在當今的線上業務中&#xff0c;要求用戶上傳身份證、駕駛證等證…

基于OpenCV圖像分割與PyTorch的增強圖像分類方案

在圖像分類任務中&#xff0c;背景噪聲和復雜場景常常會對分類準確率產生負面影響。為了應對這一挑戰&#xff0c;本文介紹了一種結合OpenCV圖像分割與PyTorch深度學習框架的增強圖像分類方案。通過先對圖像進行分割提取感興趣區域&#xff08;Region of Interest&#xff0c;R…

華為云對象存儲OBS 支持安卓/iOS/鴻蒙UTS組件

華為云對象存儲OBS 支持安卓/iOS/鴻蒙UTS組件 介紹使用前須知vue代碼調用示例權限說明API調用說明初始化配置&#xff08;openClient&#xff09;創建桶&#xff08;createBucket&#xff09;列舉桶&#xff08;listBuckets&#xff09;刪除桶&#xff08;deleteBucket&#xf…

Buildroot 2025.05 中文手冊【AI高質量翻譯】

譯文在 Github 倉庫 和 Gitee 倉庫 保持最新&#xff0c;其它平臺發的文檔可能不會與之同步。 希望能夠共同維護這個 倉庫的 Buildroot 手冊 中文譯文&#xff0c;幫助更多人真正深入學習理解&#xff0c;更好的工作、生活和創造。 關于 AI 提示詞 以及 更多工具 的收集&#…

采用ArcGIS10.8.2 進行插值圖繪制

一、最終成果圖展示 二、軟件下載 鏈接: 百度網盤 請輸入提取碼 密碼:azay 三、軟件安裝 1、在安裝之前需要關閉電腦的防火墻及殺毒軟件 設置-隱私和安全性-Windows安全中心-防火墻和網絡保護 2、軟件解壓 (1)【ArcGIS_Desktop_1082_180......】“以管理員身份運行”…

Python網安-zip文件暴力破解(僅供學習)

目錄 源碼在這里 需要的模塊 準備一個密碼本和需要破解的ZIP文件 一行一行地從密碼文件中讀取每個密碼。 核心部分 注意&#xff0c;需要修改上段代碼注釋里的這段具有編碼問題的代碼&#xff1a; 源碼在這里 https://github.com/Wist-fully/Attack/tree/cracker 需要的…

如何讓ChatGPT模仿人類寫作,降低AIGC率?

在AI技術日益普及的當下&#xff0c;ChatGPT 等大語言模型已成為許多學術與寫作任務中的得力助手。然而&#xff0c;學境思源&#xff0c;隨著各類“AI檢測系統”的出現&#xff0c;一鍵生成論文初稿&#xff01;我們也遇到一個新的問題&#xff1a;如何讓AI寫作看起來不像AI寫…

科大訊飛2025AI開發者大賽-用戶新增賽道時間規則解析

根據訓練集中的時間規則&#xff0c;對測試集中的數據推斷用戶標簽&#xff08;新用戶或老用戶&#xff09;。 時間規則如下: 針對訓練集和測試集中都存在的did&#xff1a; 找到在訓練集中標記為新用戶最晚的時間點&#xff0c;則測試集中對應did的數據在此時間點前全部為新用…

.NET C# async/定時任務的異步線程池調度方案最大線程數? = 處理器核心數 × 250

關于.NET中Threading.Timer的線程機制&#xff0c;結合線程池特性和異步協作原理分析如下&#xff1a; 一、線程復用機制 ?共享進程級線程池? Threading.Timer的回調任務?不會每次新建線程?&#xff0c;而是提交到.NET進程全局線程池統一調度&#xff0c;該線程池與async/…

Redis 高可用分片集群:主從模式與哨兵機制詳解

一、為何需要分片集群&#xff1f; 在討論具體方案之前&#xff0c;我們先明確分片集群要解決的問題&#xff1a; 單節點瓶頸&#xff1a;無論是內存容量還是處理能力&#xff08;QPS&#xff09;&#xff0c;單個 Redis 實例都有物理上限。高可用性需求&#xff1a;單點故障…

Qt readyRead信號避坑:不產生readyRead信號的解決方法

Qt readyRead信號避坑&#xff1a;不產生readyRead信號的解決方法 引言一、QSerialport的readyRead1.1 版本問題1.2 緩存問題1.3 阻塞問題 二、Q(Tcp)Socket的readyRead2.1 阻塞問題2.2 運行一段時間&#xff0c;突然不發信號2.3 和具體數據有關&#xff1f; 引言 目前沒遇到相…

大事件項目記錄10-文章分類接口開發-更新文章分類

四、更新文章分類。 CategoryController.java&#xff1a; PutMappingpublic Result update(RequestBody Validated Category category){categoryService.update(category);return Result.success();} CategoryService&#xff1a; //更新分類void update(Category category); …

AI接口使用–阿里云百煉

原文地址&#xff1a;AI接口使用–阿里云百煉 – 無敵牛 歡迎參觀我的個人博客&#xff1a;無敵牛 – 技術/著作/典籍/分享等 最近開發了一個抖音AI起名小程序&#xff0c;已經在抖音上線了&#xff0c;歡迎大家來使用。其中用到了 AI文本生成 功能&#xff0c;我用的是 阿里云…

大模型之提示詞工程入門——解鎖與AI高效溝通的“鑰匙”

一、什么是提示詞工程&#xff1f; 提示詞工程&#xff08;Prompt Engineering&#xff09; 是一門通過設計、優化輸入文本&#xff08;Prompt&#xff09;來引導大語言模型&#xff08;LLM&#xff09;生成高質量輸出的技術。它不僅是AI應用的核心環節&#xff0c;也是連接人…