Binlog(二進制日誌)是 MySQL 複制、備份、審計、異構同步的基石。本文從儲存格式、寫入流程、IO_CACHE 封裝、主從協議、Relay Log 關係五個維度,深度剖析 Binlog 內部運作機制,並回答五個核心問題,助您建立精準的心智模型。
0xFE 0x62 0x69 0x6E (「feBin」)
[Client SQL]
↓
[Parser/Resolver/Optimizer/Executor]
↓
[Storage Engine Handler::ha_write_row / ha_update_row / ha_delete_row]
↓ (事務提交階段)
[THD::binlog_query()] → [MYSQL_BIN_LOG::write()]
↓
[IO_CACHE (binlog_cache / stmt_cache)] -- 記憶體緩衝
↓ (事務提交 / 非事務語句結束)
[flush_to_disk()] → [my_write() / pwrite()] → [OS Page Cache] → [Disk]
↓
[Sync 策略: sync_binlog=1 時 fsync()]
binlog_cache (事務性):儲存事務內所有事件,Commit 時一次性刷入主 Binlogstmt_cache (非事務性):每條語句直接寫入LOCK_log 全域互斥鎖序列化多線程寫入,確保 Binlog 位點單調遞增。MySQL 將檔案讀寫封裝為 IO_CACHE 結構體 (sql/io_cache.h):
read_cache / write_cache:緩衝區指標、剩餘空間、檔案描述符my_b_read() / my_b_write():帶緩衝的讀寫 API
[Master] [Slave]
│ │
├─ COM_BINLOG_DUMP (binlog_pos, flags) ───→ │ (IO Thread)
│ │
│ ← Binlog Events (packet stream) ────────┤
│ ├─ Write to Relay Log (IO_CACHE)
│ │
│ ├─ SQL Thread 讀取 Relay Log
│ │ ↓
│ │ Parse Event → Execute SQL
│ │ ↓
│ │ Update Relay Log Info (position)
│ │
│ ← ACK (GTID/Position) ──────────────────┤ (半同步/GTID 模式)
| 線程 | 職責 | 關鍵狀態 |
|---|---|---|
| Master Dump Thread | 讀取本地 Binlog 發送給 Slave | Sending binlog event to slave |
| Slave IO Thread | 接收事件、寫入 Relay Log | Waiting for master to send event |
| Slave SQL Thread | 讀取 Relay Log、重放 SQL | Reading event from the relay log |
relay-log.xxxxxxrelay_log_info_repository=TABLE (MySQL 5.6+) 將位點存入 mysql.slave_relay_log_info,Crash Safe| 問題 | 回答 | 解析 |
|---|---|---|
| 1. Binlog 格式? | 二進制順序儲存,不加密,不壓縮。Event-based,含 Header+Body。 | 三種行級格式:STATEMENT/ROW/MIXED,由 binlog_format 控制。 |
| 2. Binlog 使用 WAL? | No。Binlog 是邏輯日誌(記錄 SQL 或行變更),非物理 Redo Log。InnoDB 才有 Redo Log (WAL)。 | Binlog 寫入不強制 fsync (除非 sync_binlog=1);Redo Log 嚴格遵循 WAL。 |
| 3. Master 發送 Binlog 用記憶體副本? | 無法確定,極大概率是讀磁盤發送。Dump Thread 直接 my_b_read() 讀取 Binlog 檔案 (經 OS Page Cache) 封包發送。 | 若 Binlog 仍在 Page Cache 則屬記憶體讀取;否則產生磁碟 I/O。大量歷史 Binlog 傳送會佔用 I/O 頻寬。 |
| 4. Relay Log 使用 WAL? | Yes。Slave IO Thread 寫入 Relay Log 並 fsync() (受 sync_relay_log 控制),SQL Thread 再讀取重放。 | 這是 Slave Crash Safe 的關鍵:Relay Log 已持久化,重啟後可續傳、續重放。 |
| 5. Binlog 與 Relay Log SQL 是否一致? | 網路可靠前提下,Yes。事件內容原樣轉發,無語義轉換。GTID 模式下更嚴格保證一致性。 | 若網路傳輸錯誤 (Checksum 失敗),IO Thread 會重試或中斷,不會寫入壞事件。 |
sync_binlog=1 + innodb_flush_log_at_trx_commit=1 是「雙 1」黃金標準,犧牲 ~10-20% 寫入效能換取極致一致性。binlog_cache_size 增大、使用 SSD、啟用 binlog_checksum=CRC32 減少網路重傳。binlog_expire_logs_seconds (8.0) 替代 expire_logs_days,秒級精度控制保留窗口。Binlog 看似簡單的追加檔案,實則承載了 MySQL 複制、備份、審計、CDC 的全部重擔。透徹其格式、寫入、傳輸、重放全鏈路,才能在架構設計、故障排查、效能調優中游刃有餘。下一篇我們將探討 Facebook 萬億級 MySQL 架構演進與避坑指南,敬請期待。