首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 崩潰無法啟動?innodb_force_recovery 緊急搶救實戰指南

     編輯:MySQL 資料庫相關知識

磁碟故障、掉電、殺進程、OOM Killer 導致 MySQL 異常關閉,重啟時卡在 InnoDB: Doing recovery... 階段最終報 mysqld got signal 11 (Segmentation fault) 退出。此時數據頁、Redo Log、Undo Log 可能已損壞,正常崩潰恢復失效。innodb_force_recovery 是最後的「核武器級」搶救手段 — **跳過損壞頁檢查、跳過事務回滾、跳過 Redo Log 前滾**,強行拉起實例導出數據重建。本文記錄一次真實生產搶救全過程。

故障現場

  • 環境:MariaDB 5.5.37 (兼容 MySQL 5.5)
  • 觸發:磁碟陣列故障導致主機硬崩潰
  • 錯誤日誌關鍵片段:
    InnoDB: Doing recovery: scanned up to log sequence number 9120034833
    150125 16:12:51 InnoDB: Starting an apply batch of log records to the database...
    InnoDB: Progress in percents: 5 6 7 ... 40
    150125 16:12:51 [ERROR] mysqld got signal 11 ;  -- Segfault,恢復過程中訪問非法記憶體

分析:Redo Log 在應用階段遇到損壞頁/邏輯錯誤觸發 Segfault,屬於 **嚴重元數據/數據頁損壞**,常規恢復無效。

innodb_force_recovery 參數詳解 (1-6 級遞增)

在 [mysqld] 區段設置 innodb_force_recovery = N,級別包含關係 (N 級包含 N-1 級所有行為):

級別常量名行為風險
1SRV_FORCE_IGNORE_CORRUPT忽略檢測到的損壞頁,繼續啟動可能讀取到髒數據
2SRV_FORCE_NO_BACKGROUND阻止 Master Thread 運行 (阻止 Full Purge、Merge 等後台操作)無法清理 Undo Log,空間增長
3SRV_FORCE_NO_TRX_UNDO不執行事務回滾 (視未提交事務為已提交)數據不一致風險極高
4SRV_FORCE_NO_IBUF_MERGE不合併 Insert Buffer二級索引可能缺失記錄
5SRV_FORCE_NO_UNDO_LOG_SCAN不掃描 Undo Log,視未提交事務為已提交同級別 3,更徹底
6SRV_FORCE_NO_LOG_REDO**不執行 Redo Log 前滾** (最暴力,直接掛載.ibd)數據可能停留在舊版本

核心限制:innodb_force_recovery > 0 時,實例進入 **唯讀模式** — 僅允許 SELECT、CREATE、DROP,**禁止 INSERT/UPDATE/DELETE**。

關鍵坑點:innodb_purge_threads 與 force_recovery 衝突導致無限循環

MySQL 5.5/5.6 源碼邏輯:啟動時等待 Purge Thread 啟動,但 force_recovery >= 2 會阻止 Master Thread,導致 Purge Thread 永不啟動,主線程陷入 Waiting for the background threads to start 無限循環。

解法:同時設置 innodb_purge_threads = 0 (禁用獨立 Purge Thread)。

實戰搶救步驟 (本案例成功路徑)

  1. 修改配置 (my.cnf):
    [mysqld]
    innodb_force_recovery = 6
    innodb_purge_threads = 0
  2. 重啟 MySQL:
    systemctl restart mysqld
    # 或 service mysql restart
    日誌顯示 Crash recovery finished.、ready for connections. → **實例掛載成功!**
  3. 立即導出數據 (唯讀模式下)**:
    mysqldump -u root -p --all-databases --single-transaction --routines --triggers > /backup/full_dump_$(date +%F).sql
    必須加 --single-transaction** 保證導出一致性視圖 (雖然實例唯讀,但習慣加上)。
  4. 驗證導出文件完整性** (行數、檔案大小、關鍵表抽樣)。
  5. 恢復配置並重建**:
    # 註釋 force_recovery 恢復 purge_threads
    # innodb_force_recovery = 6
    # innodb_purge_threads = 0  (恢復預設 1 或 4)
    
    systemctl restart mysqld  # 正常模式啟動
    mysql -u root -p < /backup/full_dump_$(date +%F).sql  # 導入新實例

版本差異提示

  • MySQL 5.5 及之前:innodb_purge_threads 預設 1,force_recovery > 1 **必須** 設 innodb_purge_threads = 0。
  • MySQL 5.6+:innodb_purge_threads 預設 1,同樣需關閉。
  • MySQL 5.7/8.0:Purge 線程架構重構,innodb_purge_threads 可動態調整,但 force_recovery >= 2 仍建議暫設為 0 避免啟動卡死。

事後複盤與預防

  1. 根因:磁碟陣列故障 → 寫入掛起/部分寫入 → Redo Log / 數據頁損壞 → 崩潰恢復失敗。
  2. 數據損失評估:force_recovery=6 跳過 Redo Log 前滾,**未提交事務視為已提交,已提交但未刷盤的事務可能丟失**。需結合 Binlog (若開啟) 或業務日誌對賬確認損失範圍。
  3. 預防措施**
  • RAID 卡 BBU (電池備份單元) 健康監控** — 保證掉電時緩存數據刷盤。
  • 開啟雙重寫緩衝** (innodb_doublewrite=ON,預設開啟) — 防止頁寫入一半損壞。
  • MySQL 5.6+ 開啟 Crash-Safe Replication** (relay_log_info_repository=TABLE, master_info_repository=TABLE, relay_log_recovery=ON) — 從庫 Relay Log 元數據存表,避免 Error 1594/1236。
  • 定期物理備份 (xtrabackup) + 邏輯備份 (mysqldump) 雙軌制** — RPO/RTO 可控。
  • 異地多活/備份** — 單機房災難級故障兜底。

避坑指南

  • 切勿在生產長期開啟 force_recovery** — 唯讀模式、後台線程停止、數據一致性無保障,僅用於緊急導出。
  • 不要嘗試修復 .ibd 文件** — 無官方修復工具,第三方工具 (如 innochecksum) 僅能校驗,無法修復邏輯錯誤。
  • 導出前務必驗證業務關鍵表數據完整性** — 甚至可接受部分非核心表丟失,核心表必須 100% 正確。

這次搶救雖然成功,但屬於「醫生開刀前先簽生死狀」的極端手段。**堅實的備份體系、健康的存儲硬體、Crash-Safe 配置,才是資料庫生存的根本**。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved