如何為 MySQL 主從架構設定自動故障切換

你可以藉助 Keepalived、MySQL Utilities 或 MySQL InnoDB Cluster 等工具,為 MySQL 主從架構設定自動故障切換。本文將帶你依序完成前置條件準備、複寫設定、故障切換工具部署、測試以及最佳實務。Keepalived 透過管理虛擬 IP 實現高可用,而 MySQL Utilities 和 InnoDB Cluster 則可以在主庫故障時提升新的主庫。本文預設你已經掌握基本的 MySQL 指令,並且至少準備好了兩台伺服器。你將學會如何在主庫當機時保護資料一致性,並盡可能維持業務可用性。按照本文步驟操作,你可以建立一套值得信賴的故障切換方案。
MySQL 複寫的前置條件
伺服器與網路要求
在建置任何故障切換方案之前,你至少需要兩台伺服器。其中一台作為主庫,負責處理所有寫入流量;另一台作為從庫,接收主庫的全部變更副本。為每台主機分配靜態 IP 位址、可解析的主機名稱,以及穩定可靠的網路連線。連線中斷是觸發故障切換最常見的原因之一,因此網路本身就是架構設計的一部分,而不是事後補救項目。
故障切換通常會因三類問題被觸發:節點之間的網路中斷、主庫所在機器當機,或者 MySQL 服務本身被關閉。對故障切換工具來說,這三種情況表現並不相同,因此你必須為每種情況設計清楚的應對策略。你也可以採用主主架構,也就是每個主庫各自複寫到自己的從庫。這種設計增加了資料備援,但你的故障切換方案仍然必須在每個主庫各自擁有從庫的前提下,準確提升正確的節點。務必充分測試這種拓撲,因為一旦提升錯誤節點,就會破壞整個架構的一致性。
MySQL 安裝與版本相容性
在所有節點上安裝相同版本的 MySQL。版本不一致可能會在一些細節上破壞 MySQL 複寫,尤其是在二進位日誌格式於不同版本之間發生變化時更是如此。在開始設定之前,先檢查每台主機上的版本,並優先升級不一致的伺服器。在 Ubuntu 或 Debian 上,主設定檔位於 /etc/mysql/mysql.conf.d/mysqld.cnf,稍後你需要在主庫上修改它。
在調整複寫設定之前,先規劃好監控方案。你需要一種方法來快速偵測主庫是否失效,也需要一種方法來確認副本是否健康且已經追平。提前確定由哪種工具負責監控叢集、檢查頻率是多少,以及故障時通知誰。這裡的規劃越扎實,實際故障發生時就越不容易出意外。伺服器準備完成且版本一致後,就可以進入複寫設定階段。
設定 MySQL 主從複寫
設定主庫伺服器
先從你選定為主庫的那台機器開始。在 Ubuntu 或 Debian 上,開啟 /etc/mysql/mysql.conf.d/mysqld.cnf,設定唯一的伺服器 ID,啟用二進位日誌,並指定日誌檔案名稱。這些設定可以讓主庫記錄每一次變更,並將其提供給各個副本。
[mysqld]
server-id = 1
log_bin = mysql-bin
binlog_do_db = appdb儲存檔案後重新啟動服務。接著,建立一個專門用於 MySQL 複寫的帳號,並授予它 REPLICATION SLAVE 權限。短暫鎖表後,讀取目前的二進位日誌位置,並記錄日誌檔名和偏移量。這個位置就是每個從庫開始複寫資料的起點。
設定從庫並啟動複寫
切換到從庫主機,編輯它自己的設定檔。為其分配不同的伺服器 ID,然後重新啟動服務。接著使用你剛才記錄的日誌檔案和位置,透過 CHANGE MASTER TO 陳述式將從庫指向主庫。
CHANGE MASTER TO
MASTER_HOST='192.0.2.10',
MASTER_USER='repl',
MASTER_PASSWORD='secret',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=154;
START SLAVE;執行 SHOW SLAVE STATUS,並確認 Slave_IO_Running 和 Slave_SQL_Running 都顯示為 Yes。若你需要設定一個主庫同時複寫到多個從庫,Oracle Utilities 可以自動化這一步。透過在主庫寫入一筆記錄、再到從庫讀取該記錄,測試 MySQL 複寫是否正常。接著在兩端執行校驗和比對,以驗證資料一致性,確保複寫鏈路真正可靠。到這一步,一個健康的從庫就已經能夠鏡像主庫,並準備好接入故障切換工具。
為 MySQL 設定自動故障切換
現在,你已經讓 MySQL 複寫正常運作。下一步就是加入一個可以在主庫故障時自動接手的機制。生產環境中主要有兩種思路:Keepalived 負責在主機之間漂移虛擬 IP;MySQL Utilities 和 InnoDB Cluster 則直接將從庫提升為主庫。你也可以組合使用這些工具,以獲得更高的資料備援和可靠性。
使用 Keepalived 與虛擬 IP
Keepalived 執行於兩台伺服器上,並透過 VRRP 共用一個浮動 IP 位址。正常情況下,這個虛擬 IP 由主庫持有;一旦主庫發生故障,Keepalived 就會將該 IP 漂移到從庫。應用程式始終連線到同一個位址,因此幾乎感受不到切換過程。這種設計在盡量少改動應用架構的前提下,實現了高可用。
Keepalived 的設定檔位於 /etc/keepalived/keepalived.conf。在主庫上,你需要定義一個健康檢查指令碼以及一個 VRRP 實例。下面的範例展示了來自實際部署的語法結構。
將這份設定複製到從庫,並把狀態改成 BACKUP,同時將優先級降低為 101。然後在兩台機器上重新啟動 keepalived 服務。該服務每兩秒檢查一次 MySQL 狀態。當主庫當機後,健康檢查會失敗,備庫會在幾秒內接管虛擬 IP。如此一來,你無須修改應用設定,也能獲得故障切換能力。
使用 MySQL Utilities 或 InnoDB Cluster
MySQL Utilities 提供了兩個處理主庫故障切換的命令列工具。mysqlrpladmin 用於執行受控切換,而 mysqlfailover 則會持續監控主庫,並在主庫故障時自動觸發故障切換。
你可以透過執行 mysqlfailover --master=root@utils1:3306 --discover-slaves-login=root --rediscover 進入監控模式。它會每隔幾秒檢查一次主庫狀態。一旦發現故障,它會識別最合適的從庫進行提升。該工具還會在提升前嘗試從其他從庫補齊缺失事件。你也可以限制哪些從庫有資格被提升,或者設定自訂的故障切換前後指令碼。
MySQL InnoDB Cluster 則採用了另一種思路。它基於 Group Replication,而 Group Replication 提供的是同步複寫。下表比較了 Group Replication 與傳統非同步主從複寫之間的差異。
比較項目 | MySQL Group Replication | 傳統主從(非同步)複寫 |
|---|---|---|
故障切換速度 | 自動故障切換,幾乎可實現零停機;透過法定多數機制防止腦裂 | 需要人工故障切換,或依賴外部工具介入,因此會產生停機;難以滿足最小停機時間的高可用要求 |
一致性 | 單主模式下可實現零資料遺失;透過共識協定進行同步提交 | 如果主庫在副本拉取二進位日誌事件前崩潰,就存在資料遺失風險;複寫延遲還會導致讀取舊資料,並在故障切換後帶來資料不一致 |
權衡點 | 由於共識機制,寫入延遲更高;部署更複雜,並且更依賴網路品質 | 寫入延遲較低,但一致性保障較弱 |
如果你需要強一致性,並且能夠接受更高的寫入延遲,那麼請選擇 Group Replication。如果你更重視較簡單的部署方式和較低的執行開銷,那麼傳統複寫搭配 Keepalived 或 MySQL Utilities 會更適合。無論選擇哪種方案,都要徹底測試故障切換設定。模擬主庫崩潰,並驗證虛擬 IP 是否發生漂移、從庫是否被正確提升。
測試故障切換與最佳實務
模擬主庫故障
在真正發生故障之前,你必須證明你的設定確實可用。停止主庫上的 MySQL 服務,並觀察系統行為。Keepalived 會透過健康檢查指令碼偵測到程序失效,並在幾秒內將虛擬 IP 漂移到從庫。你的應用程式無須人工介入,就能重新連線到新的位址。
最好在維護視窗期間執行這類演練。確認從庫已經被提升為主庫,並且能夠正常接受寫入。同時檢查舊主庫恢復後,是否能重新以副本身分加入叢集。Keepalived 負責處理 IP 漂移,但你的提升指令碼仍然需要在新主庫上重設複寫關係。故障切換完成後,還要驗證複寫健康監控工具是否顯示狀態正常。
避免腦裂與資料遺失
腦裂指的是兩個節點都認為自己是主庫,並同時接受寫入,最終導致資料分叉。MySQL InnoDB Cluster 透過法定多數機制來防止這種情況。只有當大多數節點都確認後,寫入操作才會提交。這種基於 Paxos 的共識機制,正是它在網路分區場景下防止腦裂的核心原理。
叢集規模 | 所需法定多數 | 可容忍節點故障數 |
|---|---|---|
1 個節點 | 1 | 0 |
3 個節點(建議) | 2 | 1 |
5 個節點 | 3 | 2 |
7 個節點 | 4 | 3 |
偶數節點叢集並不安全。若發生 50/50 分裂,任何一側都無法取得多數,因此雙方都會拒絕寫入。這種做法犧牲了一部分可用性,但換來了資料一致性保護。
請遵循以下規則來保護你的資料:先確認主庫確實已經失效,再執行故障切換;一次故障只切換一次,絕不要提升一個不一致的從庫;所有寫入都必須只送到主庫;故障切換完成後,及時更新應用設定,使其指向新的主庫;並且一定要先在預發佈或測試環境中驗證設定。
自動故障切換建立在三個支柱之上:可用的複寫鏈路、可靠的故障切換工具,以及反覆的測試演練。應根據你的拓撲選擇合適的工具。Keepalived 適合簡單的虛擬 IP 故障切換,而 MySQL Utilities 或 InnoDB Cluster 更適合具備拓撲感知能力的主庫提升場景。
接下來,你應該加入監控、定期安排故障切換演練,並在每次測試後複查 MySQL 日誌。每一次演練都應先在測試環境完成,再推廣到正式環境。這樣的習慣能更好地保護資料,並維持高可用性。
常見問題
自動故障切換一般需要多長時間?
Keepalived 每兩秒檢查一次主庫狀態,一旦健康檢查失敗,就會漂移虛擬 IP,因此切換通常會在數秒內完成。MySQL Utilities 和 InnoDB Cluster 提升新主庫的耗時也大致相似。實際所需時間仍取決於你的監控間隔和網路狀況。
沒有虛擬 IP 也能實現故障切換嗎?
可以。MySQL Utilities 和 InnoDB Cluster 都可以直接提升副本,因此你的應用程式需要重新連線到新的主機。虛擬 IP 的優勢在於保持存取位址不變,從而免去應用層重新設定。具體採用哪種方式,應根據你的應用能接受多大改動來決定。
故障切換後,舊主庫會怎麼樣?
舊主庫恢復後,會以副本身分重新加入。你的提升指令碼會透過 CHANGE MASTER TO 將它重新指向新的主庫。務必確認複寫恢復正常,並確保在故障期間沒有任何寫入落到這個已被降級的節點上。
自動故障切換會導致寫入遺失嗎?
在非同步複寫架構中,確實有這種可能。如果主庫在副本拉取到最新二進位日誌事件之前崩潰,那麼最近的一部分變更可能會遺失。InnoDB Cluster 透過同步的 Group Replication 和基於法定多數的提交機制避免了這個問題。而傳統架構則需要接受一個小範圍的資料遺失視窗。
要實現安全故障切換,至少需要多少個節點?
三個節點可以形成 2 的法定多數,並容忍 1 個節點故障。偶數節點叢集並不安全,因為發生 50/50 分裂時,任何一側都拿不到多數。對於簡單的虛擬 IP 故障切換,Keepalived 雙機方案已經可行;但對於依賴法定多數機制的方案,則需要使用奇數節點。
