高可用架構#
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)複製流程詳解#
- 備庫連接主庫:執行
CHANGE MASTER設置主庫信息 - 啟動複製線程:
START SLAVE啟動 io_thread 和 sql_thread - 主庫發送日誌:主庫讀取 binlog 發送給備庫
- 備庫接收存儲:io_thread 寫入中轉日誌(relay log)
- 備庫執行日誌:sql_thread 解析執行 relay log
雙 M 結構#
flowchart LR
subgraph MM["雙 M 結構"]
A["節點 A"] <-->|"互為主備<br/>binlog 雙向同步"| B["節點 A'"]
end
style A fill:#bbdefb
style B fill:#c8e6c9| 狀態 | 節點 A | 節點 A' |
|---|---|---|
| 正常時 | 主庫 | 備庫 |
| 切換後 | 備庫 | 主庫 |
雙 M 結構的優勢是切換時不需要修改主備關係,只需切換業務流量。
循環複製問題#
雙 M 結構中,為避免循環複製,MySQL 使用 server_id 機制:
- 兩個庫的 server_id 必須不同
- 備庫重放日誌時,生成的 binlog 保留原 server_id
- 收到 server_id 與自己相同的日誌時,直接丟棄
binlog 格式選擇#
三種格式對比#
| 格式 | 內容 | 優點 | 缺點 |
|---|---|---|---|
| statement | SQL 原文 | 日誌小 | 可能主從不一致 |
| row | 行資料變更 | 資料一致 | 日誌較大 |
| mixed | 自動選擇 | 折中方案 | 已較少使用 |
為什麼推薦 row 格式#
-- statement 格式的風險
DELETE FROM t WHERE a >= 4 AND t_modified <= '2018-11-10' LIMIT 1;
-- 主備可能使用不同索引,刪除不同的行!
-- row 格式記錄被刪除行的主鍵
-- 備庫一定會刪除相同的行row 格式的額外好處是誤操作恢復:DELETE 誤刪可從 binlog 轉成 INSERT;INSERT 誤插可從 binlog 轉成 DELETE;UPDATE 誤改可交換前後資料重新執行。
主備延遲#
延遲的定義#
主備延遲 = 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.7 - LOGICAL_CLOCK
- 同時處於 prepare 狀態的事務可以並行
- 通過
binlog_group_commit_sync_delay增加並行度
MySQL 5.7.22 - 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 = ONGTID 的工作原理#
- 備庫把自己的 GTID 集合發給主庫
- 主庫計算差集,找出備庫缺少的事務
- 從第一個缺失事務開始發送 binlog
- 自動處理主備切換,無需手動找位點
一主多從架構#
架構圖#
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_Running | IO 線程狀態 | != Yes |
| Slave_SQL_Running | SQL 線程狀態 | != Yes |
備庫設置只讀的原因#
- 防止誤操作
- 防止切換時雙寫
- 用於判斷節點角色
readonly 對 super 權限用戶無效,複製線程可以正常執行。
本章小結#
| 主題 | 要點 |
|---|---|
| 複製原理 | io_thread 接收,sql_thread 執行 |
| binlog 格式 | 推薦 row,數據一致且可恢復 |
| 主備延遲 | 大事務、單線程複製是主因 |
| 並行複製 | 5.7.22 WRITESET 效果最好 |
| 切換策略 | 可靠性優先,減少延遲 |
| GTID | 自動位點,簡化切換 |
高可用的關鍵是減少主備延遲。延遲越小,切換越快,RPO 和 RTO 都更優。