目錄
- 深入分析與利弊對比
- 1. `AFTER_COMMIT` (不推薦)
- 2. `AFTER_SYNC` (強烈推薦,MySQL 8.0 默認)
- 總結與強烈建議
- 最佳實踐
MySQL 半同步復制主要有兩種實現方式,其核心區別在于主庫何時回復客戶端事務提交成功(即何時認為事務完成),這直接影響了數據安全性和性能。這兩種方式由參數 rpl_semi_sync_master_wait_point
控制(在 MySQL 5.7 及以后版本中,推薦使用 AFTER_SYNC
):
AFTER_COMMIT
(MySQL 5.6 / 5.7 早期默認,現已不推薦)AFTER_SYNC
(MySQL 5.7 及以后推薦配置,MySQL 8.0 默認)
深入分析與利弊對比
特性 | AFTER_COMMIT | AFTER_SYNC (推薦) |
---|---|---|
等待點 | 主庫事務提交后等待ACK | 主庫事務寫入Binlog后、提交前等待ACK |
控制參數 | rpl_semi_sync_master_wait_point = AFTER_COMMIT | rpl_semi_sync_master_wait_point = AFTER_SYNC |
數據安全性 | 較低 (存在數據丟失風險) | 較高 (強一致性保障) |
數據一致性 | 主庫可見數據 != 從庫已接收數據 | 主庫可見數據 == 從庫已接收數據 |
故障切換風險 | 高 (可能導致數據丟失) | 低 (保障故障切換數據一致) |
性能 | 相對稍好 | 相對稍差 (但差距通常很小) |
客戶端感知延遲 | 提交后等待ACK,延遲較大 | 寫入Binlog后等待ACK,提交在ACK后,延遲稍小 |
推薦版本 | MySQL 5.6 / 5.7 早期 | MySQL 5.7+ (強烈推薦), MySQL 8.0 (默認) |
1. AFTER_COMMIT
(不推薦)
-
工作流程:
- 客戶端發起
COMMIT
。 - 主庫在存儲引擎內部提交事務,使事務對主庫上的其他會話可見。
- 主庫將事務的 Binlog 發送給從庫。
- 主庫等待至少一個啟用了半同步復制的從庫返回 ACK 確認(表示該從庫已接收并寫入其自己的 Relay Log)。
- 主庫收到 ACK 后,回復客戶端
COMMIT
成功。 - 從庫的 SQL 線程異步應用 Relay Log 中的事務。
- 客戶端發起
-
優點:
- 相對于
AFTER_SYNC
,在等待 ACK 期間主庫上的鎖(如 InnoDB 行鎖)可能釋放得更早(因為事務已在主庫提交),理論上在高并發、鎖競爭激烈的場景下對主庫的吞吐量有輕微優勢(但實際差距通常很小)。
- 相對于
-
缺點 (重大風險 - 主要不推薦的原因):
- 數據丟失風險: 這是最核心的問題。如果在主庫提交后(步驟2)、但在收到從庫 ACK 之前(步驟4-5之間)主庫發生崩潰且無法恢復,那么:
- 主庫上該事務已提交,對客戶端來說是成功的。
- 客戶端認為數據已安全存儲。
- 但該事務的 Binlog 可能尚未發送到從庫,或者從庫接收到了但尚未寫入 Relay Log 并返回 ACK。
- 當故障切換到新的主庫(原從庫)時,這個“已提交”的事務會丟失!因為它在新主庫上不存在。這違反了用戶對“半同步”保障數據安全的預期。
- 數據不一致窗口: 在主庫提交后(客戶端可見數據)、到從庫確認并應用事務之前,主庫和從庫的數據是不一致的。其他在主庫上讀取到該數據的會話,如果查詢從庫,會看到舊數據。
- 客戶端感知延遲: 客戶端需要等待主庫提交 加 網絡往返(等待 ACK)的時間,感知到的提交延遲較長。
- 數據丟失風險: 這是最核心的問題。如果在主庫提交后(步驟2)、但在收到從庫 ACK 之前(步驟4-5之間)主庫發生崩潰且無法恢復,那么:
2. AFTER_SYNC
(強烈推薦,MySQL 8.0 默認)
-
工作流程:
- 客戶端發起
COMMIT
。 - 主庫將事務寫入 Binlog 文件(通常是
fsync
到磁盤)。 - 主庫將事務的 Binlog 發送給從庫。
- 主庫等待至少一個啟用了半同步復制的從庫返回 ACK 確認(表示該從庫已接收并寫入其自己的 Relay Log)。
- 主庫收到 ACK 后,在存儲引擎內部提交事務,使事務對主庫上的其他會話可見。
- 主庫回復客戶端
COMMIT
成功。 - 從庫的 SQL 線程異步應用 Relay Log 中的事務。
- 客戶端發起
-
優點:
- 強數據安全保證 (核心優勢): 這是推薦
AFTER_SYNC
的根本原因。只有在確保事務 Binlog 至少已安全傳遞到一個從庫(寫入其 Relay Log)后,主庫才提交事務并對客戶端報告成功。因此:- 如果主庫在回復客戶端成功之前崩潰,事務在主庫上未提交(雖然 Binlog 已寫入),客戶端知道失敗。
- 如果主庫在回復客戶端成功之后崩潰(即已提交),那么該事務的 Binlog 必定已存在于至少一個從庫的 Relay Log 中。故障切換到該從庫后,這個事務一定能被新主庫應用,不會丟失。這滿足了半同步復制防止數據丟失的設計目標。
- 數據一致性窗口更小: 一旦主庫提交(步驟5),數據在主庫可見,此時確認該數據已存在于至少一個從庫的持久化存儲(Relay Log)中。雖然從庫可能還未應用,但數據已安全抵達。其他會話在主庫讀到數據后,即使立即查從庫看到舊數據,也知道這是因為復制延遲(異步應用),而不是數據丟失風險。
- 客戶端感知延遲稍低: 客戶端等待的時間是 Binlog 寫入(通常很快) + 網絡往返(等待 ACK)的時間。主庫自身的提交操作(步驟5)是在后臺完成的,不阻塞客戶端響應(雖然客戶端已收到成功響應,但其他會話看到數據可能還有極短暫延遲)。
- 強數據安全保證 (核心優勢): 這是推薦
-
缺點:
- 鎖持有時間稍長: 在等待 ACK 期間(步驟4),事務在主庫的存儲引擎層尚未提交,因此它持有的鎖(如 InnoDB 行鎖)不會被釋放。這可能在極高并發、鎖競爭非常激烈的場景下,對主庫的吞吐量造成極其輕微的影響(但現代硬件和網絡下,這種影響通常可以忽略不計,遠小于數據安全的收益)。這就是所謂的“無損半同步”的代價(保障數據無損)。
- 對網絡延遲更敏感: 等待 ACK 發生在提交之前,網絡延遲會直接影響事務提交的整體延遲和吞吐量。需要確保網絡質量良好。
總結與強烈建議
AFTER_COMMIT
應避免使用: 其設計缺陷(主庫提交后等待 ACK)導致在主庫崩潰時存在已提交事務丟失的風險,這違背了使用半同步復制提高數據安全性的初衷。MySQL 社區和官方早已認識到此問題。AFTER_SYNC
是當前的最佳實踐和標準配置:- 它真正實現了半同步復制防止數據丟失的核心價值:確保每個對客戶端報告成功提交的事務,其 Binlog 必定已持久化在至少一個從庫上。
- 它提供了更強的數據一致性和故障切換安全性。
- 其潛在的性能開銷(鎖持有時間稍長)在絕大多數生產環境中微乎其微,且是保障數據安全必須付出的合理代價。
- MySQL 8.0 已默認使用
AFTER_SYNC
,這充分說明了其重要性。
最佳實踐
- 始終配置
rpl_semi_sync_master_wait_point = AFTER_SYNC
(MySQL 5.7+) 或直接使用 MySQL 8.0 (默認即為AFTER_SYNC
)。 - 確保至少有一個穩定且低延遲的從庫啟用了半同步復制 (
rpl_semi_sync_slave_enabled = ON
)。 - 合理設置
rpl_semi_sync_master_timeout
(等待 ACK 的超時時間)。太短容易退化為異步,太長在主庫故障時影響可用性。需要根據網絡情況和業務容忍度權衡。 - 監控半同步狀態:檢查
Rpl_semi_sync_master_status
(主庫是否啟用了半同步),Rpl_semi_sync_master_clients
(連接的半同步從庫數量),Rpl_semi_sync_master_yes_tx
/Rpl_semi_sync_master_no_tx
(成功/失敗通過半同步提交的事務數) 等狀態變量。 - 理解半同步只能保證 Binlog Event 傳輸到從庫 Relay Log 的持久化,并不保證從庫 SQL 線程已應用。要保證讀從庫的強一致性,需要結合其他機制(如 MySQL Group Replication, InnoDB Cluster, 或外部一致性讀方案)。
- 對于極致性能要求且可容忍少量數據丟失的場景,純異步復制仍是選項。對于零數據丟失要求,需要結合
AFTER_SYNC
和更高級別的 HA 方案(如 MGR 或同步復制集群)。
結論:選擇半同步復制時,務必使用 AFTER_SYNC
模式。AFTER_COMMIT
模式存在固有的數據丟失風險,不應在新部署中使用。MySQL 8.0 的默認設置已明確指向 AFTER_SYNC
,這代表了官方對數據安全最佳實踐的確認。