InnoDB 核心機制深度解析:Redo Log、Undo Log、Checkpoint 與崩潰恢復原理
InnoDB 透過 Redo Log(重做日誌) 保證事務持久性,Undo Log(回滾日誌) 保證原子性與 MVCC。本文從 LSN、髒頁、WAL、Checkpoint、崩潰恢復等核心概念切入,系統闡述其運作原理、配置調優與故障排查。
一、核心概念速覽
1. LSN (Log Sequence Number)
- 無符號 64 位整數,單調遞增,代表日誌字節偏移量。
- 每個頁面、Redo Log、Checkpoint 都有 LSN,通過 LSN 定位日誌位置、判斷頁面是否需恢復。
- 查看:
SHOW ENGINE INNODB STATUS 中的 LOG 區塊。
2. 髒頁
- Buffer Pool 中被修改但未刷盤的頁面。
- Flush List:各 Buffer Pool Instance 維護,按修改 LSN 排序,最老頁面(最小 LSN)優先刷盤。
- 刷盤觸發條件:
- Redo Log 循環寫滿(需推進 Checkpoint)
- Buffer Pool 空間不足需淘汰髒頁
- 系統空閒時後台線程定期刷新
- Checkpoint 觸發
- 關鍵參數:
innodb_max_dirty_pages_pct (預設 90%) 控制髒頁比例上限。
3. WAL (Write-Ahead Logging)
「日誌先行」:事務提交前,Redo Log 必須持久化;數據頁面可延遲刷盤。兼顧持久性與效能。
二、Undo Log:原子性與 MVCC 基石
儲存位置
- 預設在系統表空間
ibdata1。
- 5.6+ 支援獨立 Undo 表空間(
innodb_undo_tablespaces、innodb_undo_directory)。
分類
- Insert Undo:僅事務本身可見,提交後即可丟棄。
- Update Undo:UPDATE/DELETE 產生,需維護多版本鏈,支援 MVCC 讀取歷史版本。
版本鏈遍歷
舊事務讀取時順著 Undo 鏈尋找可見版本。鏈過長(長事務未提交、大量更新)會導致讀取效能下降(參考 Bug #69812)。
三、Redo Log:持久性保障
檔案結構
ib_logfile0, ib_logfile1 ... 循環寫入。
- 總大小 =
innodb_log_files_in_group × innodb_log_file_size。
- 目錄由
innodb_log_group_home_dir 控制。
寫入機制
- 用戶線程生成 Redo 記錄寫入 Log Buffer(記憶體)。
- LGWR (Log Writer) 觸發條件將 Buffer 刷盤:
- 事務提交(受
innodb_flush_log_at_trx_commit 控制)
- Log Buffer 使用量達 1/2(舊版 1/3)
- 每秒定時刷新
- Checkpoint 需要
- 順序寫入,IO 效能高。
關鍵參數 innodb_flush_log_at_trx_commit
| 值 | 行為 | 持久性 | 效能 |
| 1 (預設) | 每次提交 fsync 刷盤 | 最強(不丟事務) | 最低 |
| 2 | 提交寫 OS Cache,每秒 fsync | 最多丟 1 秒事務 | 高 |
| 0 | 不主動刷盤,靠後台每秒 fsync | 掛掉可能丟事務 | 最高 |
四、Checkpoint:推進恢復起點
定期將「已刷盤的最老髒頁 LSN」記錄為 Checkpoint,恢復時只需重放 Checkpoint 之後的 Redo Log。
四類 Checkpoint
- Sharp Checkpoint:正常關庫時,刷新所有髒頁,LSN 推進到最新。
- Master Thread Checkpoint:後台線程每秒/每 10 秒異步刷新部分髒頁(1.2+ 移至 Page Cleaner 線程)。
- FLUSH_LRU_LIST Checkpoint:LRU 末尾淘汰髒頁時強制刷盤(1.2+ 異步化)。
- Async/Sync Flush Checkpoint:Redo Log 空間不足(超 76% 未 Checkpoint)觸發強制刷髒頁,可能阻塞用戶線程(1.2+ 異步化)。
- Dirty Page Too Much Checkpoint:髒頁比例超
innodb_max_dirty_pages_pct 強制刷盤。
五、崩潰恢復流程
- 讀取最新 Checkpoint LSN。
- Redo 階段:從 Checkpoint LSN 開始正向掃描 Redo Log,重放所有已提交事務的修改(Rolling Forward)。
- Undo 階段:識別未提交事務(有 BEGIN 無 COMMIT),利用 Undo Log 反向回滾其修改(Rolling Back)。
得益於 LSN 有序性,InnoDB 僅需處理增量日誌,恢復速度快。
六、Log Buffer 與 IO 優化
innodb_log_buffer_size:預設 8MB~64MB(視版本)。大事務系統可調大至 64MB~256MB,減少 LGWR 喚醒頻率。
- 批量提交:將多條 DML 合併為一個事務,減少 fsync 次數。
- 大量載入:
SET autocommit=0; SET unique_checks=0; SET foreign_key_checks=0; 載入後再開啟。
七、實戰監控指標
| 指標 | 含義 | 異常判斷 |
| Innodb_log_waits | 等待 Redo Log 空間計數 | >0 表示 Log 滿導致阻塞,需加大 log file size |
| Innodb_buffer_pool_wait_free | 等待 Buffer Pool 空閒頁計數 | >0 表示髒頁刷盤跟不上 |
| Innodb_log_write_requests / Innodb_log_writes | 寫請求 vs 實際寫入 | 比值過高說明 Buffer 過小或提交頻繁 |
| Innodb_os_log_fsyncs | fsync 次數 | 配合 flush_log_at_trx_commit 分析 |
八、總結:參數調優清單
[mysqld]
# Redo Log 檔案組:建議 4 個 x 1GB = 4GB,支撐高寫入
innodb_log_files_in_group = 4
innodb_log_file_size = 1G
# 提交刷盤策略:核心業務用 1,非核心可用 2
innodb_flush_log_at_trx_commit = 1
# 髒頁比例上限:SSD 可調 70-80,HDD 保持 90
innodb_max_dirty_pages_pct = 75
# Log Buffer:大事務系統調大
innodb_log_buffer_size = 64M
# Page Cleaner 線程數:1.2+ 獨立線程,建議 4-8
innodb_page_cleaners = 4
# LRU 掃描深度:配合 page_cleaners
innodb_lru_scan_depth = 2048
延伸閱讀:Percona Blog、MySQL 官方手冊 InnoDB 章節、姜承尉《MySQL 內核:InnoDB 存儲引擎》。
- 上一篇文章: Linux 部署 MySQL 5.7 完整教程:tar.gz 二進制包解壓安裝法
- 下一篇文章: Linux 部署 MySQL 5.7:tar.gz 二進制包解壓安裝法(精簡版)
Copyright ©
程式碼之家 All Rights Reserved