熱門分類
載入中…
目錄0%

🗄️ MySQL / MariaDB Active-Active 高可用架構:雙主同步 + 自動故障切換完整指南

    🗄️ MySQL / MariaDB Active-Active 高可用架構:雙主同步 + 自動故障切換完整指南

    當網站或系統成長到一定規模,「一台資料庫 + 一台備援」的 Active-Passive 架構,很快就會遇到極限: 讀寫都擠在同一台主機、備援平時閒置、故障切換還可能需要人工介入。 這時候,「Active-Active 雙主+自動故障切換」會是自然的下一步。 本文以 MySQL / MariaDB 為主,從概念、架構選型、部署實作到故障情境與排錯整理一套完整實務指南。

    📌 一、Active-Active 是什麼?與 Active-Passive 有何不同?

    先用最簡單的方式,把兩種常見架構拆開來看:

    • Active-Passive(主備)
      一台主庫處理所有讀寫,另一台備庫透過複寫(同步或非同步)跟上主庫。平時備庫不對外服務,只有主庫掛掉時才切換。
    • Active-Active(雙主 / 多主)
      多個節點 同時對外提供服務,流量可以被分散到不同 DB,理論上可以同時提升吞吐與可用性。

    兩者最關鍵的差異在於:

    • 資料一致性難度:Active-Active 必須處理「多個節點同時寫入同一筆資料」的衝突問題。
    • 流量分散方式:Active-Passive 基本上所有寫入都打到同一台;Active-Active 則需要搭配 Load Balancer / 中介層 管流量。
    • 故障行為:Active-Passive 只有一個「主」需要切換;Active-Active 則要處理「某個節點死掉後,如何快速把流量導向其他健康節點」。

    因此,Active-Active 不是多開幾台 DB、互相做主從 就能完成。 你需要的是:支援多主架構的複寫技術+設計良好的流量入口+故障偵測機制

    📚 二、常見 MySQL / MariaDB Active-Active 架構選項總覽

    實務上,想在 MySQL / MariaDB 世界達成 Active-Active,常見選項大致如下:

    1. 傳統雙主複寫(Master-Master Replication)— ❌ 不建議作為主力

    這是很多人最先想到的做法:

    • A 主 <=> B 主:互相做主從複寫,兩邊都可以寫。
    • 在應用程式端或 Proxy 端,同時把流量送到兩邊。

    問題是:

    • 衝突處理很麻煩:同時寫同一筆資料,最後誰為準?
    • Binlog 延遲 / 迴圈複寫:設定不慎會出現奇怪的循環與延遲。
    • 自動故障切換缺乏共識機制:容易出現 Split Brain,兩邊都以為自己是主。

    因此,雙主複寫通常只在「流量不大、操作者極熟悉風險」的場景使用,並不適合作為泛用的 Active-Active 架構。

    2. MariaDB Galera / Percona XtraDB Cluster — ✅ 最常見的 Active-Active 方案之一

    Galera Cluster 是一種 同步多主複寫 的技術,MariaDB / Percona 等都提供整合套件。 在 Galera 中,所有節點共享同一個「寫入視圖」,透過一致性演算法,確保所有節點看見的寫入順序相同。

    特性:

    • 每個節點都可以讀寫(多主)。
    • 透過 wsrep_* 參數控制複寫行為與 Flow Control。
    • 支援 同步或者「準同步」 的寫入確認機制。

    優點:

    • 原生支援多主寫入,設計就是為 Active-Active 而生。
    • 內建 Quorum / 仲裁,較容易避免腦裂。
    • 有完整的社群實務與文件,搭配 HAProxy / ProxySQL 成熟度高。

    3. MySQL Group Replication / InnoDB Cluster — ✅ 官方多主方案

    MySQL 官方則提供 Group Replication 及其上層封裝 InnoDB Cluster, 一樣提供 多主寫入 + 共識協議 + 自動故障處理 的能力。

    特性:

    • 支援 Single-Primary 以及 Multi-Primary 模式。
    • 搭配 MySQL Router 可提供智慧路由(讀寫分離、故障節點剔除)。
    • 與 MySQL Shell 整合,建立與維運相對直覺。

    如果你偏好「全部用官方元件」,InnoDB Cluster + Router 會是很好的選擇。

    4. Proxy 層(ProxySQL / HAProxy)+ VIP(Keepalived)— Active-Active 的「入口大腦」

    無論是 Galera 或 InnoDB Cluster,要讓外部應用程式「簡單連一個位址就好」,幾乎都會搭配:

    • Proxy 層:ProxySQL 或 HAProxy,負責:
      • 健康檢查(Health Check)。
      • 把流量分配到健康節點。
      • 讀寫分離(看架構需求)。
    • 虛擬 IP(VIP)或 DNS: 透過 Keepalived / LVS / DNS(短 TTL)讓應用端只記住單一連線位址。這也是故障切換的入口。

    🧠 三、設計 Active-Active 架構前,必須先想清楚的幾件事

    1. 一致性模型: 你的系統是偏向「強一致」還是「可接受短暫不一致」?
    2. 寫入衝突: 有沒有大量跨節點同時更新同一筆資料的情況?
    3. 故障切換策略: 誰來決定「哪台下線」?是 ProxySQL / HAProxy / Router / Orchestrator 還是人手?
    4. 維運能力: 團隊是否熟悉這些元件的排錯?(Flow Control、GTID、仲裁、Split Brain…)

    以下我們用兩個常見實作範例,帶你從零組出一套可以上線的架構。

    🏗️ 四、範例架構一:MariaDB Galera + HAProxy + Keepalived(常見企業組合)

    1. 架構拓樸示意

                     ┌─────────────────────────────┐
                     │         應用程式層(Web / API) │
                     └─────────────▲──────────────┘
                                   │ 連線(單一 VIP)
                            VIP: 10.0.0.100:3306
                                   │
                    ┌──────────────┴──────────────┐
                    │                             │
         HAProxy + Keepalived A         HAProxy + Keepalived B
            10.0.0.11                        10.0.0.12
                    │                             │
          ┌─────────┴────────┐          ┌────────┴─────────┐
          │                  │          │                  │
       DB1 (Galera)      DB2 (Galera)  DB3 (Galera)   (可選 Arbitrator)

    設計重點:

    • 3 個 Galera 節點維持 Quorum,避免雙節點腦裂。
    • 2 台 HAProxy + Keepalived 組成前端雙機,對外只暴露 VIP。
    • 應用程式記住的只有 10.0.0.100:3306,背後切換完全透明。

    2. Galera 基本安裝與設定(示意)

    以下以 MariaDB + Galera 為例,每台 DB 節點的 /etc/my.cnf.d/galera.cnf 可能包含:

    [galera]
    wsrep_on                 = ON
    wsrep_provider           = /usr/lib64/galera/libgalera_smm.so
    
    # 集群名稱
    wsrep_cluster_name       = 'prod-galera-cluster'
    
    # 集群成員清單(所有節點一致)
    wsrep_cluster_address    = 'gcomm://10.0.0.21,10.0.0.22,10.0.0.23'
    
    # 本節點位址(每台不同)
    wsrep_node_address       = '10.0.0.21'
    wsrep_node_name          = 'db1'
    
    # 複寫設定
    binlog_format            = ROW
    default_storage_engine   = InnoDB
    innodb_autoinc_lock_mode = 2
    
    # 流量控制(依實際情況調整)
    wsrep_slave_threads      = 8
    wsrep_certification_rules= STRICT

    初始化步驟(概念示意):

    1. 在第一台 DB(db1)使用 galera_new_cluster / bootstrap 方式啟動集群。
    2. 在 db2、db3 直接啟動 MariaDB,會透過 wsrep_cluster_address 找到集群並自動同步。
    3. 確認 SHOW STATUS LIKE 'wsrep_cluster_size'; 顯示節點數量正確。

    3. HAProxy 與健康檢查設定

    在 HAProxy 節點中,可設定一組後端指向 Galera 節點,並透過 mysql-check 檢查健康狀態:

    frontend mysql_front
        bind *:3306
        mode tcp
        default_backend galera_back
    
    backend galera_back
        mode tcp
        balance roundrobin
        option mysql-check user haproxy_check
        server db1 10.0.0.21:3306 check
        server db2 10.0.0.22:3306 check
        server db3 10.0.0.23:3306 check backup

    實務上可以依需求把某些節點標為 backup,或進一步利用 ProxySQL 做「寫入集中 / 讀取分散」, 例如:一台節點主負責寫入,其餘放讀取為主。

    4. Keepalived 虛擬 IP 設定

    以 A 節點為主、B 節點為備的 Keepalived 設定示意:

    vrrp_instance VI_1 {
        state MASTER
        interface eth0
        virtual_router_id 51
        priority 150
        advert_int 1
        authentication {
            auth_type PASS
            auth_pass ha-vip-pass
        }
        virtual_ipaddress {
            10.0.0.100/24 dev eth0
        }
    }

    在 B 節點則將 state 設為 BACKUPpriority 設低一些,例如 100。當 A 節點失效時,VIP 會飄到 B 節點。

    5. 故障情境簡單驗證

    • 關閉其中一個 DB 節點:確認 HAProxy 檢測到後,從後端池中移除該節點。
    • 關閉 A 節點整機:確認 VIP 飄移到 B 節點,應用程式連線不中斷(或短暫中斷後恢復)。
    • 刻意製造網路隔離:確認 Galera 的 Quorum 行為,避免雙邊都對外提供服務。

    🏗️ 五、範例架構二:MySQL InnoDB Cluster + MySQL Router + Keepalived

    若偏好 MySQL 官方技術堆疊,可以改用:

    • InnoDB Cluster:底層使用 Group Replication 完成多主複寫。
    • MySQL Router:提供智慧路由端點(讀 / 寫不同埠、故障節點剔除)。

    1. 建立 InnoDB Cluster(示意流程)

    透過 MySQL Shell 建立集群的概念示意:

    # 在 mysqlsh 中
    dba.createCluster("prodCluster", {multiPrimary: true})
    
    # 加入節點
    cluster = dba.getCluster()
    cluster.addInstance("root@10.0.0.31:3306")
    cluster.addInstance("root@10.0.0.32:3306")
    cluster.addInstance("root@10.0.0.33:3306")
    
    # 查看狀態
    cluster.status()

    設定 multiPrimary: true 後,集群中的節點都可以寫入,InnoDB Cluster 會處理寫入排序與共識。

    2. 部署 MySQL Router

    在 Router 節點上,使用 MySQL Shell 為 Router 帶出設定:

    # 產出 Router 設定
    dba.configureRouterInstance("router@10.0.0.41:6446", {
        clusterName: "prodCluster"
    })

    Router 啟動後會暴露類似:

    • 6446:讀寫端點。
    • 6447:唯讀端點。

    再搭配 Keepalived 將 Router 節點做成雙機,對外一樣只提供一個 VIP。

    ⏱ 六、自動故障偵測與 Failover 流程設計

    Active-Active 架構的重點,不只是「多台都在跑」,而是某台掛了之後能不能自動切換且不寫壞資料

    一般會拆成三個層次:

    1. 資料庫層: Galera / Group Replication 透過投票機制決定誰還在集群內。
    2. Proxy / Router 層: HAProxy / ProxySQL / MySQL Router 透過健康檢查,把「沒通」或「不在集群內」的節點踢掉。
    3. VIP / DNS 層: Keepalived 或短 TTL DNS 控制「入口在哪一台 Proxy」。

    設計原則:

    • 任一層都不要單點(Single Point of Failure)。
    • 「誰有權決定把節點踢出服務」一定要清楚(避免多頭決策)。
    • 故障偵測要有 grace period,避免短暫網路抖動帶來過度切換。

    🩹 七、常見陷阱與排錯清單

    • 腦裂(Split Brain): 網路分割後,兩邊都以為自己是主,結果同時接受寫入。
    • Flow Control 造成延遲: Galera / Group Replication 中,落後太多的節點可能拖慢整體提交速度。
    • 不當讀寫分配: 把「強一致要求」的寫入分散到多個節點,造成大量鎖競爭。
    • 健康檢查過於單純: 只檢查 3306 活著就當正常,沒有檢查「是否仍在集群內」。
    • 備份與快照不一致: 沒有意識到多主架構下備份點的選擇與一致性問題。

    建議排錯方向:

    1. 先看 DB 層集群狀態(wsrep_cluster_statuscluster.status())。
    2. 再看 Proxy 層後端池狀態(show servers state / HAProxy stats)。
    3. 最後看 VIP / DNS 的指向與 ARP 解析是否正確。

    💾 八、備份、維護與 Schema 變更策略

    Active-Active 架構下,備份與維護要特別小心:

    • 備份: 建議統一由「指定節點」執行,並確認該節點在備份期間不被 Proxy 當成主要寫入節點。
    • Schema 變更: 儘量減少大規模 ALTER,改用 Online DDL 或分批變更。
    • 維護窗口: 建議配合負載低谷,且事先模擬「節點下線 / 重新加入」流程。

    如果你已經有 PostgreSQL 50 萬筆資料實驗 那類基準環境,可以比照方式為 Active-Active 架構建立壓測腳本,測試:

    • 單節點故障時的吞吐穩定度。
    • 節點重新加入時帶來的同步負載。
    • 在大量 DML / DDL 操作下,Flow Control 的影響程度。

    🎯 九、什麼情境適合 Active-Active?什麼情境不適合?

    適合採用 Active-Active 的情境:

    • 讀寫流量都偏高,需要同時提升 吞吐與可用性
    • 服務 不能接受長時間的主備切換窗口,例如金融交易、即時訂單系統。
    • 團隊有一定的 DBA / SRE 能量,願意投資在監控與排錯流程上。

    暫時不建議採用 Active-Active 的情境:

    • 資料模型高度集中於單一幾張表,每次交易都會修改同一批 row,鎖競爭極嚴重。
    • 團隊缺乏 DBA 經驗,以往連單主複寫都常出包。
    • 系統規模尚小,一台主機 + 一台備援就足以支撐流量。

    這時候,反而建議先把基礎打好,例如:

    • 設計合理的 Active-Passive + 自動 Failover。
    • 先做 讀寫分離,把讀流量切到副本上。
    • 再逐步演進到多主架構。

    🧭 十、實作行動清單(可當專案 Checklist)

    ✅ 明確定義系統一致性需求(強一致 / 最終一致)
    ✅ 選定多主複寫方案(Galera / InnoDB Cluster / 其他)
    ✅ 規劃節點數量:至少 3 DB 節點或 2 DB + 1 Arbitrator
    ✅ 部署 Proxy 層(HAProxy / ProxySQL / MySQL Router)
    ✅ 部署 VIP / DNS 切換機制(Keepalived / 短 TTL DNS)
    ✅ 建立故障情境測試腳本(節點當機、網路中斷、重啟)
    ✅ 建立備份與還原驗證流程(定期演練)
    ✅ 針對 Flow Control / Quorum / Split Brain 建立 SOP
    ✅ 將所有步驟文件化,納入維運 Runbook

    💬 互動留言引導(Active-Active 實戰分享區)

    如果你在實作 MySQL / MariaDB Active-Active 高可用架構 的過程中:

    • 遇到 Flow Control、延遲或鎖競爭問題
    • 對 Galera / InnoDB Cluster / ProxySQL 設計有疑問
    • 或想分享你實際踩到的坑、架構拓樸

    歡迎直接在下方留言 👇 簡單描述你的 節點數量、版本、架構圖,我會把常見問題整理成後續補充篇或 FAQ 更新在本文。


    🔗 延伸閱讀

    📘 結語:從「兩台 DB」到「一整個服務系統」的思維

    很多人在談 Active-Active 架構時,直覺想到的是「把兩台資料庫做成主主複寫」; 但當你實際部署過 Galera、InnoDB Cluster、ProxySQL、HAProxy、Keepalived 等組合之後, 會發現它真正改變的是:你開始用「整個服務系統」而不是「單一資料庫」的角度在設計架構

    如果你目前正在規劃資料庫高可用升級、或者正要從 Active-Passive 過渡到 Active-Active, 很推薦把本文當成 專案 Checklist 與學習地圖, 搭配上面延伸閱讀中的 Proxmox、Linux 安全與 PostgreSQL 實驗系列,一步一步把整體基礎打穩。

    — WWFandy・MySQL / MariaDB HA 筆記

    🔗 分享這篇 LINE Facebook X

    沒有留言:

    字級