MHA 概述
什么是 MHA?
MHA(Master High Availability)是一套优秀的 MySQL 高可用环境下故障切换和主从复制的软件。
MHA 的出现就是解决 MySQL 单点的问题。
MySQL 故障切换过程中,MHA 能做到 0-30 秒内自动完成故障切换操作。
MHA 能在故障切换的过程中最大程度上保证数据的一致性,以达到真正意义上的高可用。
为什么要用 MHA?
为解决 Master 的单点故障无法自动调节的问题。
MHA 的组成
MHA 由两部分组成: MHAManager (管理节点) MHA Node (数据库节点),
MHA Manager 可以单独部署在一台独立的机器上管理多个 master-slave 集群,也可以部署在一 台 slave 节点上。
MHA Manager 会定时探测集群中的 master 节点。
当 master 出现故障时,它可以自动将最新数据的 slave 提升为新的 master, 然后将所有其他的 slave 重新指向新的 master。
MHA 的特点
自动故障切换过程中,MHA 从宕机的主服务器上保存二进制日志,最大程度的保证数据不丢失
使用半同步复制,可以大大降低数据丢失的风险,如果只有一个 slave 已经收到了最新的二进制日 志,MHA 可以将最新的二进制日志应用于其他所有的 slave 服务器上,因此可以保证所有节点的 数据一致性
目前 MHA 支持一主多从架构,最少三台服务,即一主两从
故障切换备选主库的算法
1. 一般判断从库的是从(position/GTID)判断优劣,数据有差异,最接近于 master 的 slave,成为 备选主。
2. 数据一致的情况下,按照配置文件顺序,选择备选主库。
3. 设定有权重(candidate_master = 1),按照权重强制指定备选主。
(1)默认情况下如果一个 slave 落后 master 100M 的 relay logs 的话,即使有权重,也会失效。
(2)如果 check_repl_delay = 0 的话,即使落后很多日志,也强制选择其为备选主。
MHA 工作原理
目前 MHA 主要支持一主多从的架构,要搭建 MHA, 要求一个复制集群必须最少有 3 台数据库服务 器,一主二从,即一台充当 Master,台充当备用 Master,另一台充当从库。
MHA Node 运行在每台 MySQL 服务器上
MHAManager 会定时探测集群中的 master 节点
当 master 出现故障时,它可以自动将最新数据的 slave 提升为新的 master
然后将所有其他的 slave 重新指向新的 master,VIP 自动漂移到新的 master。
整个故障转移过程对应用程序完全透明。
MHA 部署实施
#前面的内容我们已经做好的一主二从复制,接下来我们直接进行MHA的安装部署就行了
安装Mha相应软件
cpp
#在所有主机中
[root@MHA ~]# dnf install perl perl-DBD-MySQL perl-CPAN -y
[root@MHA ~]# ls
anaconda-ks.cfg mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
cpan_plugin.tar.gz mha4mysql-node-0.58-0.el7.centos.noarch.rpm
[root@MHA ~]# tar zxf cpan_plugin.tar.gz
[root@mha MHA-7]# cpan
Loading internal logger. Log::Log4perl recommended for better logging
CPAN.pm requires configuration, but most of it can be done automatically.
If you answer 'no' below, you will enter an interactive dialog for each
configuration option instead.
Would you like to configure as much as possible automatically? [yes] yes
cpan[1]> install Config::Tiny
cpan[2]> install Log::Dispatch
cpan[3]> install Mail::Sender
Specify defaults for Mail::Sender? (y/N) y
Default encoding of message bodies (N)one, (Q)uoted-printable, (B)ase64: n
cpan[4]> install Parallel::ForkManager
cpan[5]>exit
cpp
[root@MHA ~]# ls
mha4mysql-manager-0.58 mha4mysql-manager-0.58.tar.gz
cpan_plugin.tar.gz mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
mha4mysql-node-0.58-0.el7.centos.noarch.rpm
#在管理主机中安装MHA管理工具
[root@MHA ~]# rpm -ivh mha4mysql-manager-0.58-0.el7.centos.noarch.rpm mha4mysql-node-0.58-0.el7.centos.noarch.rpm --nodeps
Verifying... ################################# [100%]
准备中... ################################# [100%]
正在升级/安装...
1:mha4mysql-node-0.58-0.el7.centos ################################# [ 50%]
2:mha4mysql-manager-0.58-0.el7.cent################################# [100%]
#在其他mysql主机中
[root@mysql-1 ~]# rpm -ivh mha4mysql-node-0.58-0.el7.centos.noarch.rpm --nodeps
Verifying... ################################# [100%]
准备中... ################################# [100%]
正在升级/安装...
1:mha4mysql-node-0.58-0.el7.centos ################################# [100%]
#注意:主机之间一定要做免密登录,如何主机主机之间可以相互登录,否则会检测失败
cpp
#如下
[root@MHA ~]# ssh -l root 172.25.254.10
Activate the web console with: systemctl enable --now cockpit.socket
Register this system with Red Hat Insights: rhc connect
Example:
# rhc connect --activation-key <key> --organization <org>
The rhc client and Red Hat Insights will enable analytics and additional
management capabilities on your system.
View your connected systems at https://console.redhat.com/insights
You can learn more about how to register your system
using rhc at https://red.ht/registration
Last login: Mon Aug 10 14:54:26 2026 from 172.25.254.1
[root@mysql-1 ~]# exit
注销
Connection to 172.25.254.10 closed.
配置 MHA 的管理环境
因为我们当前只有一套主从,所以我们只需要写一个配置文件即可
rpm包中没有为我们准备配置文件的模板
可以解压源码包后在samples中找到配置文件的模板文件
cpp
[root@MHA ~]# tar zxf mha4mysql-manager-0.58.tar.gz
[root@MHA ~]# cd mha4mysql-manager-0.58/
[root@MHA mha4mysql-manager-0.58]# ls
AUTHORS COPYING lib MANIFEST README samples tests
bin debian Makefile.PL MANIFEST.SKIP rpm t
[root@MHA mha4mysql-manager-0.58]# cd samples/conf
[root@MHA conf]# ls
app1.cnf masterha_default.cnf
[root@MHA conf]# mkdir /etc/masterrha/
[root@MHA conf]# cat masterha_default.cnf app1.cnf > /etc/masterrha/app1.cnf
[root@MHA conf]# vim /etc/masterrha/app1.cnf
[server default]
user=root
password=123 #密码
ssh_user=root #ssh远程登陆用户
repl_user=lee #mysql主从复制中负责认证的用户
repl_password=123 #mysql主从复制中负责认证的用户密码
master_binlog_dir= /data/mysql #二进制日志目录
remote_workdir=/tmp #远程工作目录
secondary_check_script= masterha_secondary_check -s 172.25.254.10 -s 172.25.254.30
ping_interval=3 #每隔3秒检测一次
# master_ip_failover_script= /script/masterha/master_ip_failover
# shutdown_script= /script/masterha/power_manager
# report_script= /script/masterha/send_report
# master_ip_online_change_script= /script/masterha/master_ip_online_change
[server default]
manager_workdir=/etc/masterrha #mha工作目录
manager_log=/etc/masterrha/manager.log #mha日志
[server1]
hostname=172.25.254.10
candidate_master=1 #可能作为master的主机
check_repl_delay=0
[server2]
hostname=172.25.254.20
candidate_master=1
check_repl_delay=0 #因为这个候选主在切换的过程中一定是新的master
[server3]
hostname=172.25.254.30
no_master=1 #不会作为master的主机
cpp
[root@MHA conf]# ls
app1.cnf masterha_default.cnf
[root@MHA conf]# cd
[root@MHA ~]# rpm -ivh mha4mysql-node-0.58-0.el7.centos.noarch.rpm
Verifying... ################################# [100%]
准备中... ################################# [100%]
正在升级/安装...
1:mha4mysql-node-0.58-0.el7.centos ################################# [100%]
[root@MHA ~]# vim /usr/share/perl5/vendor_perl/MHA/NodeUtil.pm
#sub parse_mysql_version($) {
# my $str = shift;
# my $result = sprintf( '%03d%03d%03d', $str =~ m/(\d+)/g );
# return $result;
#}
#
#添加以下内容
sub parse_mysql_major_version($) {
my $str = shift;
my @nums = $str =~ m/(\d+)/g;
my $result = sprintf( '%03d%03d', $nums[0]//0, $nums[1]//0);
return $result;
}
#
#注释掉这个内容
#sub parse_mysql_major_version($) {
# my $str = shift;
# my $result = sprintf( '%03d%03d', $str =~ m/(\d+)/g );
# return $result;
#}
[root@MHA conf]# masterha_manager --help
Usage:
masterha_manager --global_conf=/etc/masterha_default.cnf
--conf=/usr/local/masterha/conf/app1.cnf
See online reference
(http://code.google.com/p/mysql-master-ha/wiki/masterha_manager) for
details.
cpp
[root@MHA ~]# masterha_check_ssh --conf=/etc/masterrha/app1.cnf
#检测网络及 ssh 免密在rhel9中因为perl版本兼容问题会有报错。但是此报错可以忽略
#检测数据主从复制情况
#在所有MySQL主机中
mysql> create user root@'%' identified with mysql_native_password by 'lee';
#允许root远程登陆
mysql> GRANT ALL ON *.* TO root@'%' ;
#执行检测
[root@mysql-mha ~]# masterha_check_repl --conf=/etc/masterha/app1.cnf
MHA 的故障切换
MHA 的故障切换过程
共包括以下的步骤:
1.配置文件检查阶段,这个阶段会检查整个集群配置文件配置
2.宕机的 master 处理,这个阶段包括虚拟 ip 摘除操作,主机关机操作
3.复制 dead master 和最新 slave 相差的 relay log,并保存到 MHA Manger 具体的目录下
4.识别含有最新更新的 slave
5.应用从 master 保存的二进制日志事件(binlog events)
6.提升一个 slave 为新的 master 进行复制 7.使其他的 slave 连接新的 master 进行复制
1.手动切换
master无故障切换
cpp
#注意:我们不能切30主机上,因为我们定义就是30 不能当master
[root@mha conf]# masterha_master_switch \
> --conf=/etc/masterha/app1.cnf \
> --master_state=alive \
> --new_master_host=172.25.254.20 \
> --new_master_port=3306 \
> --orig_master_is_new_slave \
> --running_updates_limit=10000
Mon Aug 10 22:55:05 2026 - [info] MHA::MasterRotate version 0.58.
Mon Aug 10 22:55:05 2026 - [info] Starting online master switch..
Mon Aug 10 22:55:05 2026 - [info]
Mon Aug 10 22:55:05 2026 - [info] * Phase 1: Configuration Check Phase..
Mon Aug 10 22:55:05 2026 - [info]
Mon Aug 10 22:55:05 2026 - [warning] Global configuration file /etc/masterha_def ault.cnf not found. Skipping.
Mon Aug 10 22:55:05 2026 - [info] Reading application default configuration from /etc/masterha/app1.cnf..
Mon Aug 10 22:55:05 2026 - [info] Reading server configuration from /etc/masterh a/app1.cnf..
Mon Aug 10 22:55:06 2026 - [info] GTID failover mode = 0
Mon Aug 10 22:55:06 2026 - [info] Current Alive Master: 172.25.254.10(172.25.254 .10:3306)
Mon Aug 10 22:55:06 2026 - [info] Alive Slaves:
Mon Aug 10 22:55:06 2026 - [info] 172.25.254.20(172.25.254.20:3306) Version=8 .3.0 (oldest major version between slaves) log-bin:enabled
Mon Aug 10 22:55:06 2026 - [info] Replicating from 172.25.254.10(172.25.254. 10:3306)
Mon Aug 10 22:55:06 2026 - [info] Primary candidate for the new Master (cand idate_master is set)
Mon Aug 10 22:55:06 2026 - [info] 172.25.254.30(172.25.254.30:3306) Version=8 .3.0 (oldest major version between slaves) log-bin:enabled
Mon Aug 10 22:55:06 2026 - [info] Replicating from 172.25.254.10(172.25.254. 10:3306)
Mon Aug 10 22:55:06 2026 - [info] Not candidate for the new Master (no_maste r is set)
It is better to execute FLUSH NO_WRITE_TO_BINLOG TABLES on the master before swi tching. Is it ok to execute on 172.25.254.10(172.25.254.10:3306)? (YES/no): yes
cpp
#查看集群状态
[root@mysql-1 ~]# mysql -uroot -p123 -e "show slave status\G;" | head -n 15
mysql: [Warning] Using a password on the command line interface can be insecure.
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 172.25.254.20
Master_User: lee
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-binlog.000046
Read_Master_Log_Pos: 158
Relay_Log_File: mysql-1-relay-bin.000002
Relay_Log_Pos: 331
Relay_Master_Log_File: mysql-binlog.000046
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
cpp
[root@mysql-3 ~]# mysql -uroot -p123 -e "show slave status\G;" | head -n 15
mysql: [Warning] Using a password on the command line interface can be insecure.
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 172.25.254.20
Master_User: lee
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-binlog.000046
Read_Master_Log_Pos: 158
Relay_Log_File: mysql-3-relay-bin.000002
Relay_Log_Pos: 331
Relay_Master_Log_File: mysql-binlog.000046
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
master故障后切换
cpp
[root@mysql-1 ~]# systemctl stop mysqld.service
[root@mha ~]# masterha_master_switch --master_state=dead --conf=/etc/masterha/app1.cnf --dead_master_host=172.25.254.10 --dead_master_port=3306 --new_master_host=172.25.254.20 --new_master_port=3306 --ignore_last_failover
cpp
#查看切换信息
[root@mysql-node3 ~]# mysql -uroot -plee -e "show slave status\G;" | head -n 15
mysql: [Warning] Using a password on the command line interface can be insecure.
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 172.25.254.20
Master_User: lee
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 2337
Relay_Log_File: mysql-node3-relay-bin.000002
Relay_Log_Pos: 422
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
cpp
#故障恢复
#当出现故障切换后,mha主机中会出现切换锁文件,当文件存在后不能再次执行切换
[root@mha ~]# ls /etc/masterha/
app1.cnf app1.failover.complete mha.log scripts
[root@mysql-1 ~]# systemctl restart mysqld.service
[root@mha ~]# rm -fr /etc/masterha/app1.failover.complete
[root@mysql-node2 ~]# mysql -uroot -plee -e "reset slave;"
cpp
mysql> CHANGE MASTER TO
-> MASTER_HOST='172.25.254.20',
-> MASTER_USER='lee',MASTER_PASSWORD='123',
-> MASTER_LOG_FILE='mysql-binlog.000046',
-> MASTER_LOG_POS=158;
Query OK, 0 rows affected, 8 warnings (0.02 sec)
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> show slave status;\G
cpp
[root@mysql-node1 ~]# mysql -uroot -plee -e "start slave;"
[root@mysql-node1 ~]# mysql -uroot -plee -e "show slave status\G;" | head -n 15
mysql: [Warning] Using a password on the command line interface can be insecure.
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 172.25.254.20
Master_User: lee
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 2337
Relay_Log_File: mysql-node1-relay-bin.000002
Relay_Log_Pos: 422
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
自动切换
cpp
[root@mha masterha]# masterha_manager --conf=/etc/masterha/app1.cnf
Mon Aug 10 23:53:23 2026 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.
Mon Aug 10 23:53:23 2026 - [info] Reading application default configuration from /etc/masterha/app1.cnf..
Mon Aug 10 23:53:23 2026 - [info] Reading server configuration from /etc/masterha/app1.cnf..
[root@mha masterha]# jobs
[1]+ 运行中 masterha_manager --conf=/etc/masterha/app1.cnf &
[root@mha masterha]# Creating /tmp if not exists.. ok.
Checking output directory is accessible or not..
cpp
[root@mysql-1 mysql]# systemctl stop mysqld.service
[root@mysql-3 ~]# mysql -uroot -p123 -e "show slave status\G;" | head -n 15
mysql: [Warning] Using a password on the command line interface can be insecure.
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 172.25.254.20
Master_User: lee
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-binlog.000046
Read_Master_Log_Pos: 158
Relay_Log_File: mysql-3-relay-bin.000002
Relay_Log_Pos: 331
Relay_Master_Log_File: mysql-binlog.000046
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
可以看到之前是10 现在10被停止了,所以30自动切换到了20 上
vip功能及vip的启动切换
cpp
[root@mysql-1 ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:11:d0:1c brd ff:ff:ff:ff:ff:ff
altname enp3s0
altname ens160
inet 172.25.254.10/24 brd 172.25.254.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet 172.25.254.100/24 scope global secondary eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe11:d01c/64 scope link noprefixroute
valid_lft forever preferred_lft forever
#vip 从20 迁移到 10
[root@mysql-2 ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:d9:89:68 brd ff:ff:ff:ff:ff:ff
altname enp3s0
altname ens160
inet 172.25.254.20/24 brd 172.25.254.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fed9:8968/64 scope link noprefixroute
valid_lft forever preferred_lft forever
cpp
[root@mha ~]# vim /etc/masterha/app1.cnf
master_ip_failover_script= /etc/masterha/scripts/master_ip_failover
master_ip_online_change_script= /etc/masterha/scripts/master_ip_online_change
[root@mha ~]# vim /etc/masterha/scripts/master_ip_failover
my $vip = '172.25.254.100/24';
[root@mha ~]# vim /etc/masterha/scripts/master_ip_online_change
my $vip = '172.25.254.100/24';
[root@mysql-node1 ~]# ip a a 172.25.254.100/24 dev eth0
cpp
[root@mha masterha]# chmod +x master_ip_failover master_ip_online_change
[root@mha masterha]# masterha_master_switch --conf=/etc/masterha/app1.cnf --master_state=alive --new_master_host=172.25.254.10 --new_master_port=3306 --orig_master_is_new_slave --running_updates_limit=10000
其他故障更手动切换是一样的