一、MySQL高可用之組復制(MGR)
1.1 組復制核心特性與優勢
????????MySQL Group Replication(MGR)是基于分布式一致性協議(Paxos)實現的高可用集群方案,核心特性包括:
????????自動故障檢測與恢復:集群自動檢測故障節點,并通過選舉機制產生新主節點(單主模式)。
????????數據一致性保障:讀寫事務需經過集群多數節點(>N/2)確認后才能提交,避免數據分裂。
????????彈性擴展:支持動態添加 / 移除節點,無需中斷集群服務。
????????兩種運行模式:單主模式(僅 1 個可寫節點)和多主模式(所有節點可寫)。
1.2 組復制架構原理
組復制依賴以下核心組件:
????????組通信系統(GCS):負責節點間消息傳遞(如事務日志、心跳檢測),基于 TCP 協議實現。
????????一致性協議層:采用 Paxos 算法確保事務在集群中的順序一致性。
????????事務驗證層:檢測并發事務沖突(多主模式下),避免數據不一致。
工作流程簡述:
? ? ? ? (1)主節點(單主模式)或任意節點(多主模式)接收寫事務。
????????(2)事務執行前生成預寫日志(WAL),并廣播至集群所有節點。
????????(3)所有節點驗證事務合法性(如無沖突),并通過一致性協議達成提交順序共識。
????????(4)多數節點確認后,事務在所有節點提交,確保全局一致。
1.3 單主模式組復制實現(實戰步驟)
環境準備
IP地址 | server-id | |
候選主節點 | 192.168.168.200 | 200 |
從節點1 | 192.168.168.129 | 129 |
從節點2 | 192.168.168.130 | 130 |
步驟1:所有節點基礎配置(my.cnf)
[mysqld]
# 基礎配置
server-id=200 # 每個節點唯一(200/129/130)
datadir=/data/mysql
socket=/data/mysql/mysql.sock
pid-file=/data/mysql/mysql.pid# 二進制日志與GTID(MGR依賴GTID)
log_bin=/data/mysql/binlog
binlog_format=ROW # 必須為ROW格式
log_slave_updates=ON # 從庫同步的事務寫入自身binlog
gtid_mode=ON # 啟用GTID
enforce_gtid_consistency=ON # 強制GTID一致性# 組復制相關配置
transaction_write_set_extraction=XXHASH64 # 事務寫入集提取算法
loose-group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" # 集群UUID(自定義)
loose-group_replication_start_on_boot=OFF # 不自動啟動組復制
loose-group_replication_local_address="192.168.168.200:33061" # 本節點組通信端口(每個節點修改IP)
loose-group_replication_group_seeds="192.168.168.200:33061,192.168.168.129:33061,192.168.168.130:33061" # 集群種子節點
loose-group_replication_bootstrap_group=OFF # 僅初始化集群時設為ON
loose-group_replication_single_primary_mode=ON # 啟用單主模式
????????重啟所有節點使配置生效:
systemctl restart mysqld
步驟2:創建組復制專用賬戶(所有節點執行)
????????登錄MySQL,創建用于節點間通信的賬戶:
-- 創建復制用戶(允許所有集群節點訪問)
CREATE USER 'grp_user'@'192.168.168.%' IDENTIFIED BY 'Grp@123';
-- 授予復制權限
GRANT REPLICATION SLAVE ON *.* TO 'grp_user'@'192.168.168.%';
-- 刷新權限
FLUSH PRIVILEGES;
步驟3:配置復制通道(所有節點執行)
? ? ? ? 設置基于GTID的復制通道,用于組內事務同步:
-- 停止現有復制(若有)
STOP REPLICA;-- 配置組復制通道
CHANGE REPLICATION SOURCE TO
SOURCE_USER='grp_user',
SOURCE_PASSWORD='Grp@123',
SOURCE_AUTO_POSITION=1
FOR CHANNEL 'group_replication_recovery';
步驟4:安裝組復制插件(所有節點執行)
-- 安裝組復制插件
INSTALL PLUGIN group_replication SONAME 'group_replication.so';-- 驗證插件是否安裝成功
SHOW PLUGINS LIKE 'group_replication';
????????輸出示例(狀態為ACTIVE表示成功):
+-------------------+----------+--------------------+----------------------+---------+
| Name | Status | Type | Library | License |
+-------------------+----------+--------------------+----------------------+---------+
| group_replication | ACTIVE | GROUP REPLICATION | group_replication.so | GPL |
+-------------------+----------+--------------------+----------------------+---------+
步驟5:初始化集群(僅在第一個節點執行)
????????在 192.168.168.200(候選主節點)上引導集群:
-- 啟動集群初始化(僅第一次執行)
SET GLOBAL group_replication_bootstrap_group=ON;-- 啟動組復制
START GROUP_REPLICATION;-- 關閉初始化開關(避免重復初始化)
SET GLOBAL group_replication_bootstrap_group=OFF;
步驟6:添加其他節點到集群(129和130節點執行)
-- 啟動組復制,自動加入集群
START GROUP_REPLICATION;
步驟7:驗證集群狀態
????????-- 啟動組復制,自動加入集群 START GROUP_REPLICATION;
SELECT * FROM performance_schema.replication_group_members;
????????輸出示例(單主模式下MEMBER_ROLE
為 PRIMARY 的是主節點):
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier | 200e5b9a-732b-11f0-971f-000c29d6adc7 | 192.168.168.200 | 3306 | ONLINE | PRIMARY | 8.0.40 |
| group_replication_applier | 129e5b9a-732b-11f0-971f-000c29d6adc7 | 192.168.168.129 | 3306 | ONLINE | SECONDARY | 8.0.40 |
| group_replication_applier | 130e5b9a-732b-11f0-971f-000c29d6adc7 | 192.168.168.130 | 3306 | ONLINE | SECONDARY | 8.0.40 |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
1.4 單主模式故障轉移測試
1.模擬主節點故障:在主節點(200)執行停機命令:
systemctl stop mysqld
2.查看集群狀態:在從節點(129)執行:
SELECT * FROM performance_schema.replication_group_members;
????????輸出中會顯示原主節點狀態為UNREACHABLE
,約 30 秒后集群自動選舉新主(如 129 節點變為 PRIMARY)。
3.恢復原主節點:重啟 200 節點后,自動以從節點身份加入集群:
systemctl start mysqld
????????登錄 200 節點的 MySQL,啟動組復制:
START GROUP_REPLICATION;
????????再次查看集群狀態,200 節點角色變為 SECONDARY。
1.5 多主模式組復制配置(擴展)
????????多主模式允許所有節點同時處理寫事務,適合高并發寫入場景,配置差異如下:
1.修改所有節點的my.cnf:
loose-group_replication_single_primary_mode=OFF # 關閉單主模式(啟用多主)
loose-group_replication_enforce_update_everywhere_checks=ON # 強制多主更新檢查
2.重啟節點并重新初始化集群(參考單主模式步驟5-6):
-- 在第一個節點執行
SET GLOBAL group_replication_bootstrap_group=ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group=OFF;-- 其他節點執行
START GROUP_REPLICATION;
3.驗證多主模式:所有節點的MEMBER_ROLE
均為 PRIMARY:
SELECT MEMBER_HOST, MEMBER_ROLE FROM performance_schema.replication_group_members;
1.6 組復制監控與維護
1.查看集群健康狀態:
-- 集群成員狀態
SELECT * FROM performance_schema.replication_group_members;-- 事務沖突統計(多主模式)
SELECT * FROM performance_schema.replication_group_member_stats;
2.動態添加節點:
-- 在新節點執行(參考步驟2-4配置后)
START GROUP_REPLICATION;
3.移除節點:
-- 在待移除節點執行
STOP GROUP_REPLICATION;
4.集群重啟(全部節點故障后):
-- 在任意一個節點重新引導集群
SET GLOBAL group_replication_bootstrap_group=ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group=OFF;-- 其他節點直接啟動
START GROUP_REPLICATION;
總結
????????MySQL 組復制(MGR)通過分布式一致性協議實現了自動故障轉移和數據一致性,單主模式適合讀多寫少場景,多主模式適合高并發寫入。實際部署時需注意:
????????節點數至少 3 個,確保多數派機制生效;
????????網絡延遲需控制在 100ms 以內,避免影響事務提交效率;
????????定期監控集群狀態,及時處理故障節點。
結合業務場景選擇合適的高可用架構,可有效提升 MySQL 集群的穩定性和可靠性。
二、MySQL高可用之MHA(Master High Availability)
2.1 MHA核心特性與優勢
????????MHA 是針對 MySQL 主從復制架構的高可用解決方案,通過自動監控主庫狀態、實現故障檢測與自動切換,核心特性包括:
????????自動故障轉移:主庫宕機后 10-30 秒內完成新主庫選舉與切換。
????????數據一致性保障:通過 binlog 補傳機制減少數據丟失風險。
????????零數據丟失:配合半同步復制可實現接近零數據丟失。
????????低侵入性:無需修改 MySQL 現有配置,兼容各種主從架構。
????????在線切換:支持手動觸發主從切換(如主庫升級維護)。
2.2 MHA架構原理
MHA 由兩部分組成:
????????MHA Manager:管理節點,負責監控集群狀態、觸發故障轉移。
????????MHA Node:部署在所有 MySQL 節點,提供 binlog 復制、故障檢測等功能。
故障轉移流程:
? ? ? ? 1.監控階段:Manager 通過 SSH 定期(默認 3 秒)向主庫發送 ping 包檢測存活狀態。
? ? ? ? 2.故障確認:連續 3 次 ping 失敗后,Manager 通過其他從庫確認主庫是否真的宕機。
? ? ? ? 3.選舉新主:根據從庫的日志同步進度(優先選擇最接近主庫的從庫)選舉新主。
? ? ? ? 4.故障轉移:隔離舊主庫(如關閉 VIP、防火墻阻斷);提升新主庫(執行reset slave all
);其他從庫指向新主庫(通過 relay log 補全差異);應用層切換至新主庫(如更新 VIP 指向);
2.3 MHA實戰部署(單主多從架構)
環境準備
IP地址 | 主機名 | |
MHA Manager | 192.168.168.201 | mha-manager |
MySQL 主庫 | 192.168.168.200 | master |
MySQL 從庫 1 | 192.168.168.129 | slave1 |
MySQL 從庫 2 | 192.168.168.130 | slave2 |
步驟1:配置SSH免密登錄(關鍵)
MHA Manager 需要免密登錄所有 MySQL 節點,MySQL 節點間也需要免密互通:
# 在MHA Manager節點生成密鑰
[root@mha-manager ~]# ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa# 分發密鑰到所有節點(包括自身)
[root@mha-manager ~]# for host in 192.168.168.200 192.168.168.129 192.168.168.130 192.168.168.201; dossh-copy-id -i ~/.ssh/id_rsa.pub root@$host
done# 驗證免密登錄
[root@mha-manager ~]# ssh 192.168.168.200 date
步驟2:安裝MHA軟件
所有節點安裝MHA Node
# 安裝依賴
[root@master ~]# yum install -y perl-DBD-MySQL perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager# 下載并安裝node包
[root@master ~]# wget https://github.com/yoshinorim/mha4mysql-node/releases/download/v0.58/mha4mysql-node-0.58-0.el7.noarch.rpm
[root@master ~]# rpm -ivh mha4mysql-node-0.58-0.el7.noarch.rpm
MHA Manager節點額外安裝Manager包
[root@mha-manager ~]# wget https://github.com/yoshinorim/mha4mysql-manager/releases/download/v0.58/mha4mysql-manager-0.58-0.el7.noarch.rpm
[root@mha-manager ~]# rpm -ivh mha4mysql-manager-0.58-0.el7.noarch.rpm
步驟3:配置MySQL權限
在主庫創建 MHA 專用管理用戶(從庫會同步該用戶):
-- 創建管理用戶(用于監控和故障轉移)
CREATE USER 'mha_admin'@'192.168.168.%' IDENTIFIED BY 'Mha@123';
GRANT ALL PRIVILEGES ON *.* TO 'mha_admin'@'192.168.168.%' WITH GRANT OPTION;-- 確保主從復制用戶已存在(參考1.2章節的rep用戶)
FLUSH PRIVILEGES;
步驟4:配置MHA Manager
創建配置目錄
[root@mha-manager ~]# mkdir -p /etc/mha/mysql_cluster
[root@mha-manager ~]# mkdir -p /var/log/mha/mysql_cluster
編寫集群配置文件
# /etc/mha/mysql_cluster/mha.cnf
[server default]
# 管理用戶
user=mha_admin
password=Mha@123
# 復制用戶(主從同步用)
repl_user=rep
repl_password=rep123
# 工作目錄
manager_workdir=/var/log/mha/mysql_cluster
# 日志文件
manager_log=/var/log/mha/mysql_cluster/manager.log
# SSH連接端口
ssh_port=22
# MySQL端口
mysql_port=3306
# 檢測間隔(秒)
ping_interval=3
# 二次檢查的從庫數量
secondary_check_script=masterha_secondary_check -s 192.168.168.129 -s 192.168.168.130
# 故障轉移后執行的腳本(如更新VIP)
master_ip_failover_script=/etc/mha/mysql_cluster/master_ip_failover[server1]
hostname=192.168.168.200
port=3306
# 主庫故障后禁止自動啟動
no_master=1[server2]
hostname=192.168.168.129
port=3306
# 候選主庫權重
candidate_master=1[server3]
hostname=192.168.168.130
port=3306
candidate_master=1
步驟5:編寫VIP切換腳本
創建master_ip_failover
腳本實現虛擬 IP(VIP)自動漂移:
#!/usr/bin/perl
use strict;
use warnings FATAL => 'all';
use Getopt::Long;my ($command, $ssh_user, $orig_master_host,$orig_master_ip, $orig_master_port, $new_master_host,$new_master_ip, $new_master_port, $new_master_user,$new_master_password
);# VIP配置
my $vip = '192.168.168.250/24';
my $key = '0';
my $dev = 'ens33';GetOptions('command=s' => \$command,'ssh_user=s' => \$ssh_user,'orig_master_host=s' => \$orig_master_host,'orig_master_ip=s' => \$orig_master_ip,'orig_master_port=i' => \$orig_master_port,'new_master_host=s' => \$new_master_host,'new_master_ip=s' => \$new_master_ip,'new_master_port=i' => \$new_master_port,
);exit &main();sub main {print "\n\nIN SCRIPT TEST====$command======\n\n";if ( $command eq "stop" || $command eq "stopssh" ) {my $exit_code = 1;eval {print "Disabling VIP on old master: $orig_master_host \n";&stop_vip();$exit_code = 0;};if ($@) {warn "Got Error: $@\n";exit $exit_code;}exit $exit_code;}elsif ( $command eq "start" ) {my $exit_code = 10;eval {print "Enabling VIP on new master: $new_master_host \n";&start_vip();$exit_code = 0;};if ($@) {warn $@;exit $exit_code;}exit $exit_code;}elsif ( $command eq "status" ) {print "Checking the Status of the script.. OK \n";exit 0;}else {&usage();exit 1;}
}sub start_vip() {`ssh $ssh_user\@$new_master_host \"ip addr add $vip dev $dev\"`;`ssh $ssh_user\@$new_master_host \"arping -I $dev -c 3 -s $vip 192.168.168.1 > /dev/null 2>&1\"`;
}sub stop_vip() {`ssh $ssh_user\@$orig_master_host \"ip addr del $vip dev $dev\"`;
}sub usage {print"Usage: master_ip_failover --command=start|stop|stopssh|status --orig_master_host=host --orig_master_ip=ip --orig_master_port=port --new_master_host=host --new_master_ip=ip --new_master_port=port\n";
}
賦予執行權限:
[root@mha-manager ~]# chmod +x /etc/mha/mysql_cluster/master_ip_failover
步驟6:驗證MHA環境
檢查SSH連通性
[root@mha-manager ~]# masterha_check_ssh --conf=/etc/mha/mysql_cluster/mha.cnf
輸出All SSH connection tests passed successfully.
表示成功。
檢查主從復制狀態
[root@mha-manager ~]# masterha_check_repl --conf=/etc/mha/mysql_cluster/mha.cnf
輸出MySQL Replication Health is OK.
表示成功。
步驟7:啟動MHA Manager
# 后臺啟動
[root@mha-manager ~]# nohup masterha_manager --conf=/etc/mha/mysql_cluster/mha.cnf > /var/log/mha/mysql_cluster/manager.log 2>&1 &# 查看狀態
[root@mha-manager ~]# masterha_check_status --conf=/etc/mha/mysql_cluster/mha.cnf
mysql_cluster (pid: 1234) is running(0:PING_OK), master:192.168.168.200
2.4 故障轉移測試
1.模擬主庫故障:在主庫(200)執行關機命令
[root@master ~]# systemctl stop mysqld
2.觀察MHA日志:
[root@mha-manager ~]# tail -f /var/log/mha/mysql_cluster/manager.log
日志會顯示:檢測到主庫故障 → 選舉新主(如 129)→ 轉移 VIP → 完成切換。
3.驗證結果:
? ? ? ? 查看VIP是否漂移到新主庫:
[root@slave1 ~]# ip addr show ens33 | grep 192.168.168.250
? ? ? ? 檢查從庫是否指向新主:
mysql> show replica status\G
2.5 MHA日常維護
1.手動切換主庫(如主庫升級):
[root@mha-manager ~]# masterha_master_switch --conf=/etc/mha/mysql_cluster/mha.cnf \
--master_state=alive \
--new_master_host=192.168.168.129 \
--new_master_port=3306 \
--orig_master_is_new_slave
2.重啟MHA Manager:
[root@mha-manager ~]# masterha_stop --conf=/etc/mha/mysql_cluster/mha.cnf
[root@mha-manager ~]# nohup masterha_manager --conf=/etc/mha/mysql_cluster/mha.cnf &
3.添加新從庫:配置新從庫與主庫同步;修改 mha.cnf 添加新節點配置;重新檢查并啟動 MHA;
總結:
????????MHA 通過簡潔的架構實現了 MySQL 主從集群的高可用,適合對成本敏感且已有主從架構的場景。部署時需注意:
????????嚴格配置 SSH 免密登錄(核心前提);
????????配合半同步復制減少數據丟失;
????????編寫可靠的 VIP 切換腳本(關鍵環節);
????????定期測試故障轉移流程確保可用性;
根據業務規模和一致性要求,可選擇 MHA(低成本)、MGR(強一致)或 Percona XtraDB Cluster(高并發)作為高可用解決方案。