mysql 集群技术 3.高可用之 MHA

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

其他故障更手动切换是一样的

相关推荐
Bioinfo Guy4 小时前
高分Panel复现系列|转录因子网络太乱?用模块框把重点圈出来
数据库·生物信息学·生信可视化
ltl5 小时前
Disaggregated DB 合集:Socrates、PolarDB、Taurus 的共同模式
数据库
Blossom i7 小时前
大数据预处理与采集实验一:使用Python操作MySQL数据库
数据库·mysql
InfinitePlus7 小时前
Docker MySQL搭建一主一从
mysql·docker
雾时之林8 小时前
Linux--软件管理、源码包安装
linux·服务器·数据库
老纪的技术唠嗑局10 小时前
超级干货分享:中小企业使用 OceanBase 实践经验汇总
数据库
坐吃山猪10 小时前
Docker07-MySQL
mysql·docker·容器
CLOUD ACE10 小时前
谷歌云代理|零售商Target 如何利用 Spanner Graph 提升零售发现体验并将数据库维护成本降低 50%
数据库·零售
AI大模型-小雄10 小时前
Codex写分页接口为什么越翻越慢?用Cursor Pagination解决重复与漏数据
大数据·数据库·elasticsearch·搜索引擎·chatgpt·后端开发·codex