高可用架構#

MySQL 的高可用架構是生產環境的核心保障。理解主備複製原理和切換策略,是建置可靠資料庫系統的基礎。

主備複製原理#

基本架構#

sequenceDiagram
    participant Client as 用戶端
    participant M as 主庫 A
    participant S as 備庫 B

    Client->>M: 用戶端請求
    M->>M: 執行 SQL
    M->>M: 寫 binlog

    M->>S: 傳輸 binlog (io_thread)
    S->>S: 寫入 relay log
    S->>S: 執行 relay log (sql_thread)

複製流程詳解#

  1. 備庫連接主庫:執行 CHANGE MASTER 設定主庫資訊
  2. 啟動複製執行緒START SLAVE 啟動 io_thread 和 sql_thread
  3. 主庫發送日誌:主庫讀取 binlog 發送給備庫
  4. 備庫接收儲存:io_thread 寫入中轉日誌(relay log)
  5. 備庫執行日誌:sql_thread 解析執行 relay log

雙 M 結構#

flowchart LR
    A["節點 A"] <-->|"互為主備<br/>binlog 雙向同步"| B["節點 A'"]

    style A fill:#bbdefb
    style B fill:#c8e6c9

雙 M 結構是 MySQL 高可用中常見的設定:兩個節點互為主備,正常時 A 主 A’ 備,切換後 A’ 主 A 備。最大優勢是切換時不需要修改主備關係,只需切換業務流量。

為避免循環複製,MySQL 使用 server_id 機制:兩個節點的 server_id 必須不同;備庫重放日誌時,生成的 binlog 保留原 server_id;節點收到 server_id 與自己相同的日誌時直接丟棄。

binlog 格式(複製視角)#

binlog 三種格式的完整講解見「04 日誌系統」章。本章直接採用結論:生產環境建議 binlog_format = ROW,原因如下:

  • statement 格式在主備使用不同索引時,可能刪除不同的列,導致主從資料不一致
  • row 格式記錄被影響列的主鍵,保證備庫複製的結果與主庫一致
  • row 格式同時便於誤操作恢復(可從 binlog 反推還原 SQL)

主備延遲#

延遲的定義#

主備延遲 = T3 - T1

T1: 主庫執行完事務的時間
T2: 備庫接收完 binlog 的時間
T3: 備庫執行完事務的時間

查看延遲:

SHOW SLAVE STATUS;
-- 關注 seconds_behind_master 欄位

延遲的來源#

原因解決方案
備庫機器差(IO/CPU 不足)主備對等部署
備庫壓力大(承載過多查詢)一主多從分擔讀
大事務(單事務執行時間長)拆分大事務
大表 DDL(資料表結構變更耗時)使用 gh-ost
並行複製不足(單執行緒執行)啟用並行複製

大事務是延遲的主要原因之一。主庫事務執行 10 分鐘,備庫就會延遲 10 分鐘。

並行複製#

演進歷程#

MySQL 5.5: 單執行緒複製
    ↓
MySQL 5.6: 按庫並行
    ↓
MySQL 5.7: 基於 LOGICAL_CLOCK
    ↓
MySQL 5.7.22: WRITESET 策略

並行複製策略#

版本策略並行條件限制
MySQL 5.6按庫並行不同庫的事務單庫場景無效
MySQL 5.7LOGICAL_CLOCK同時 prepare 的事務需調整 binlog_group_commit_sync_delay
MySQL 5.7.22WRITESET未修改相同列的事務需額外記憶體維護 writeset
-- 設定並行複製策略
SET GLOBAL slave_parallel_type = 'LOGICAL_CLOCK';
SET GLOBAL slave_parallel_workers = 16;

-- MySQL 5.7.22+
SET GLOBAL binlog_transaction_dependency_tracking = 'WRITESET';

主備切換策略#

可靠性優先策略#

1. 等待 seconds_behind_master < 5s
2. 主庫設定 readonly = true
3. 等待 seconds_behind_master = 0
4. 備庫設定 readonly = false
5. 業務切換到備庫

特點

  • 有短暫不可用時間
  • 保證資料一致性

可用性優先策略#

1. 備庫設定 readonly = false
2. 業務切換到備庫
3. 等待同步完成

特點

  • 幾乎無不可用時間
  • 可能資料不一致

推薦使用可靠性優先策略。對於資料服務,資料可靠性通常比可用性更重要。

異常切換#

主庫故障時,無法等待延遲歸零:

延遲時間影響
很小快速切換,影響小
較大要麼等待(不可用),要麼立即切換(可能丟資料)

減少主備延遲是提高可用性的關鍵。延遲越小,切換越快,可用性越高。

GTID 模式#

什麼是 GTID#

GTID(Global Transaction Identifier)= server_uuid:gno

  • server_uuid:執行個體的唯一識別
  • gno:事務序號,每次提交遞增

GTID 的優勢#

傳統位點方式的問題

CHANGE MASTER TO
  MASTER_LOG_FILE='mysql-bin.000001',
  MASTER_LOG_POS=154;
-- 需要手動計算位點,容易出錯

GTID 方式

CHANGE MASTER TO
  MASTER_AUTO_POSITION=1;
-- 自動找到正確的同步位置

啟用 GTID#

-- my.cnf
gtid_mode = ON
enforce_gtid_consistency = ON

GTID 的工作原理#

  1. 備庫把自己的 GTID 集合發給主庫
  2. 主庫計算差集,找出備庫缺少的事務
  3. 從第一個缺失事務開始發送 binlog
  4. 自動處理主備切換,無需手動找位點

一主多從架構#

架構圖#

flowchart TB
    M["主庫 A"]
    M -->|binlog| S1["備庫 A'"]
    M -->|binlog| S2["從庫 B"]
    M -->|binlog| S3["從庫 C"]

    style M fill:#fff3e0
    style S1 fill:#c8e6c9
    style S2 fill:#e3f2fd
    style S3 fill:#e3f2fd

主庫故障切換#

使用 GTID 模式時,從庫只需執行:

CHANGE MASTER TO
  MASTER_HOST='new_master_ip',
  MASTER_AUTO_POSITION=1;
START SLAVE;

系統自動計算同步位點,大大簡化了切換流程。

最佳實踐#

參數設定#

-- binlog 格式
binlog_format = ROW

-- 啟用 GTID
gtid_mode = ON
enforce_gtid_consistency = ON

-- 並行複製
slave_parallel_type = LOGICAL_CLOCK
slave_parallel_workers = 16

-- 備庫唯讀
read_only = 1

監控指標#

指標說明告警閾值
seconds_behind_master主備延遲秒數> 30s
Slave_IO_RunningIO 執行緒狀態!= Yes
Slave_SQL_RunningSQL 執行緒狀態!= Yes

備庫設定唯讀的原因#

  1. 防止誤操作
  2. 防止切換時雙寫
  3. 用於判斷節點角色

readonly 對 super 權限使用者無效,複製執行緒可以正常執行。

本章小結#

主題要點
複製原理io_thread 接收,sql_thread 執行
binlog 格式推薦 row,資料一致且可恢復
主備延遲大事務、單執行緒複製是主因
並行複製5.7.22 WRITESET 效果最好
切換策略可靠性優先,減少延遲
GTID自動位點,簡化切換

高可用的關鍵是減少主備延遲。延遲越小,切換越快,RPO 和 RTO 都更優。