InnoDB 源碼分析:事務日誌寫入時機與 flush 機制(一)
Redo Log 是 InnoDB 實現事務持久化 (Durability) 的核心,WAL (Write-Ahead Logging) 機制確保「先寫日誌,再刷數據頁」。本文分析 innodb_flush_log_at_trx_commit 三種模式、innodb_flush_method 交互關係、Linux 核心 I/O 路徑。
兩階段持久化路徑
用戶執行緒 → Redo Log Buffer (記憶體)
↓ innodb_flush_log_at_trx_commit 控制
OS File System Cache / Page Cache (核心記憶體)
↓ fsync() / fdatasync() / O_DIRECT
物理磁碟 (Redo Log Files: ib_logfile0, ib_logfile1...)
核心參數:innodb_flush_log_at_trx_commit
| 值 | Buffer → OS Cache | OS Cache → 磁碟 | 持久性 | 效能 | 風險 |
| 1 (預設) | 每次 Commit | 每次 Commit (fsync) | 最強 (ACID D) | 最低 | 無 |
| 2 | 每次 Commit | 每秒背景執行緒 | 可能丟 1 秒 | 高 | OS Crash 丟失 OS Cache 內日誌 |
| 0 | 每秒背景執行緒 | 每秒背景執行緒 | 最弱 | 最高 | MySQL Crash 丟失 1 秒 + OS Crash 疊加 |
關鍵參數:innodb_flush_method
| 值 | 數據檔案開啟 | Redo Log 開啟 | Flush 方式 | 適用場景 |
| O_DIRECT (推薦) | O_DIRECT | O_DIRECT | fsync() | 生產環境、RAID 卡帶 BBU、NVMe |
| O_DSYNC | 正常 | O_DSYNC | 寫入即同步 | 無 BBU RAID、極度重視持久性 |
| fsync (預設) | 正常 | 正常 | fsync() | 測試環境、簡單儲存 |
| littlesync/nosync | 正常 | 正常 | 無/延遲 | 僅測試、極度追求速度 |
參數交互關係圖解
innodb_flush_log_at_trx_commit = 1 + innodb_flush_method = O_DIRECT
┌─────────────────────────────────────────────────────────────┐
│ Commit │
│ ↓ │
│ memcpy to Log Buffer │
│ ↓ │
│ write() → OS Cache (O_DIRECT 繞過 Page Cache 直接寫入) │
│ ↓ │
│ fsync() → 物理磁碟 (等待完成返回) │
│ ↓ │
│ Commit 返回成功 │
└─────────────────────────────────────────────────────────────┘
innodb_flush_log_at_trx_commit = 2 + innodb_flush_method = O_DIRECT
┌─────────────────────────────────────────────────────────────┐
│ Commit │
│ ↓ │
│ memcpy to Log Buffer │
│ ↓ │
│ write() → OS Cache │
│ ↓ │
│ 返回成功 (不等待 fsync) │
│ │
│ 背景執行緒 (每秒): │
│ fsync() → 物理磁碟 │
└─────────────────────────────────────────────────────────────┘
Linux 核心層面補充
O_DIRECT:繞過 Page Cache,直接 DMA 到磁碟控制器,避免雙重快取 (InnoDB Buffer Pool + OS Page Cache) 造成記憶體浪費與 CPU 拷貝開銷
fsync():確保數據寫入磁碟物理介質 (含控制器快取),fdatasync() 僅同步數據不更新 inode 元數據,稍快
- RAID 卡 BBU (Battery Backed Unit) / FBWC (Flash Backed Write Cache):掉電保護控制器快取,允許
innodb_flush_log_at_trx_commit=2 獲得高效能且風險可控
源碼關鍵入口
// log/log0log.cc
log_buffer_flush_to_disk() // 核心 flush 邏輯
log_write_up_to(lsn, flush_to_disk) // 寫入至指定 LSN
// srv/srv0srv.cc
srv_master_thread() // 背景每秒 flush、checkpoint
// trx/trx0trx.cc
trx_commit_low() // Commit 時觸發 flush 決策
常見誤區
| 誤區 | 事實 |
| O_DIRECT 只影響數據檔 | 同時影響 Redo Log 檔案開啟模式 |
| flush_method 決定 flush 時機 | flush_method 決定「如何 flush」,時機由 flush_log_at_trx_commit 決定 |
| 設為 2 就不安全 | 配合 BBU/FBWC 的 RAID 卡,2 是生產常用高效能配置 |
| 0 模式完全不 fsync | 背景執行緒仍每秒 fsync,只是 Commit 不等待 |
生產建議配置組合
# 金融核心、強一致性要求
innodb_flush_log_at_trx_commit = 1
innodb_flush_method = O_DIRECT
sync_binlog = 1
# 一般業務、高併發、有 BBU RAID
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
sync_binlog = 1000 (或 1)
# 僅讀副本、可重建環境
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
sync_binlog = 0
理解 WAL 兩階段持久化路徑與參數交互,是診斷「寫入延遲高」、「主從延遲大」、「崩潰恢復慢」等核心問題的前提。