首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL Binlog 內部機制深度解析:從寫入流程到主從複制的核心原理

     編輯:MySQL 綜合教學

Binlog(二進制日誌)是 MySQL 複制、備份、審計、異構同步的基石。本文從儲存格式、寫入流程、IO_CACHE 封裝、主從協議、Relay Log 關係五個維度,深度剖析 Binlog 內部運作機制,並回答五個核心問題,助您建立精準的心智模型。

一、Binlog 物理格式

  • 檔案頭:4 Bytes Magic Number 0xFE 0x62 0x69 0x6E (「feBin」)
  • 基本單位:Log Event,獨立、無互相引用、順序追加
  • Event Header:19 Bytes (固定) + Variable Part
    • Timestamp (4B)、Type Code (1B)、Server ID (4B)、Event Length (4B)、Next Position (4B)、Flags (2B)
  • Event Body:依 Type 而異(Query_event、Rows_event、GTID_event、Rotate_event、Format_description_event 等)
  • 無加密、無壓縮,純二進制順序寫入

二、寫入流程:從 SQL 到 Binlog


[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()]

關鍵點

  1. 兩層快取:
    • binlog_cache (事務性):儲存事務內所有事件,Commit 時一次性刷入主 Binlog
    • stmt_cache (非事務性):每條語句直接寫入
  2. 寫入順序保證:LOCK_log 全域互斥鎖序列化多線程寫入,確保 Binlog 位點單調遞增。
  3. Crash Safe 設計:
    • 事務:先寫 Binlog (含 XID_event),再引擎 Commit (InnoDB Redo Log fsync) — Binlog 先行
    • 若 Crash 發生在兩者之間:重啟後 InnoDB 回滾未提交事務,Binlog 含 XID 但無 Commit,備份端不會重放 → 一致性

三、IO_CACHE 抽象層

MySQL 將檔案讀寫封裝為 IO_CACHE 結構體 (sql/io_cache.h):

  • read_cache / write_cache:緩衝區指標、剩餘空間、檔案描述符
  • my_b_read() / my_b_write():帶緩衝的讀寫 API
  • Binlog 讀寫、Load Data Infile、Select Into OUTFILE 均複用此層

四、主從複制協議


[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 發送給 SlaveSending binlog event to slave
Slave IO Thread接收事件、寫入 Relay LogWaiting for master to send event
Slave SQL Thread讀取 Relay Log、重放 SQLReading event from the relay log

Relay Log 特性

  • 格式同 Binlog,但名稱固定為 relay-log.xxxxxx
  • WAL (Write-Ahead Logging):Slave 先寫 Relay Log (fsync),再由 SQL Thread 重放 → 確保不丟事件
  • relay_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 會重試或中斷,不會寫入壞事件。

六、實務啟示

  1. sync_binlog=1 + innodb_flush_log_at_trx_commit=1 是「雙 1」黃金標準,犧牲 ~10-20% 寫入效能換取極致一致性。
  2. 大規模主從環境,Master Dump Thread I/O 爭用 可緩解:binlog_cache_size 增大、使用 SSD、啟用 binlog_checksum=CRC32 減少網路重傳。
  3. 異構同步 (Kafka/Canal/Debezium) 本質上也是「偽裝成 Slave 的 Dump Thread 客戶端」,理解 Binlog Event 結構是解析器開發的前提。
  4. binlog_expire_logs_seconds (8.0) 替代 expire_logs_days,秒級精度控制保留窗口。

Binlog 看似簡單的追加檔案,實則承載了 MySQL 複制、備份、審計、CDC 的全部重擔。透徹其格式、寫入、傳輸、重放全鏈路,才能在架構設計、故障排查、效能調優中游刃有餘。下一篇我們將探討 Facebook 萬億級 MySQL 架構演進與避坑指南,敬請期待。

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