Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySQL MHA 高可用集群

MySQL MHA 高可用集群搭建过程详解

作者:云边有个小代码

MHA 是一套优秀的、开源的 MySQL 高可用性解决方案,它的核心目标是在 MySQL 主从复制环境中,实现主库故障时的自动故障转移和快速切换,尽可能保证数据库服务的连续性,这篇文章主要介绍了MySQL MHA 高可用集群搭建指南,需要的朋友可以参考下

一、MHA 是什么?

MHA 是一套优秀的、开源的 MySQL 高可用性解决方案。它的核心目标是在 MySQL 主从复制环境中,实现主库故障时的自动故障转移和快速切换,尽可能保证数据库服务的连续性。

MHA 的组成

一个典型的 MHA 集群包含以下组件:

  1. MySQL Master:主库,负责读写。
  2. MySQL Slave:一个或多个从库,复制主库的数据。
  3. MHA Manager管理节点。这是 MHA 的核心,通常部署在一台独立的服务器上。它负责监控所有 MySQL 节点,并在主库故障时执行故障转移操作。
  4. MHA Node数据节点。由主库以及从库共同组成,这是一个运行在每个 MySQL 服务器(无论是主库还是从库)上的脚本集合。它负责执行 Manager 发出的具体命令,比如切换虚拟 IP、对比日志等。

MHA 的核心工作原理

MHA 的工作原理可以概括为:一个聪明的“大脑”(Manager)时刻监控着整个 MySQL 集群,一旦“首领”(Master)倒下,它会立刻根据数据的新旧程度选出一个最合适的“新首领”,并设法找回“老首领”没来得及交代的“遗言”(未同步的日志),最终让所有“部下”(Slaves)效忠于“新首领”,从而快速恢复秩序。

MHA 的工作流程可以分为两大阶段:日常监控阶段故障转移阶段

阶段一:日常监控

  1. Manager 监控所有节点:MHA Manager 会周期性地(例如每秒一次)通过 SSH 连接到所有的 MySQL 节点(Master 和 Slaves),执行 SELECT 1 之类的简单查询来检查它们的存活状态。
  2. 收集复制拓扑信息:Manager 会从各个节点获取关键的复制信息,如:
    • 谁是当前的主库?
    • 谁是从库?
    • 每个从库的复制位置(Master_Log_File, Read_Master_Log_Pos)是多少?

这个阶段,Manager 对整个集群的健康状况和结构了如指掌。

阶段二:故障转移(核心)

当 Manager 检测到主库无法连接或已经宕机时,它会自动触发故障转移流程。这个过程非常精细,是其高可靠性的关键。

第1步:验证主库故障

第2步:选择新的主库

第3步:补偿丢失的数据(关键步骤)

第4步:切换从库到新主库

第5步:虚拟 IP 切换(可选但常用)

第6步:通知管理员(可选)

至此,整个故障转移过程完成,集群恢复了服务。

MHA 的优势

  1. 数据一致性高:通过补偿未发送的 binlog,最大程度避免数据丢失。
  2. 故障转移快速:通常在 10-30 秒内即可完成自动切换。
  3. 自动化和易用性:无需人工干预,提供了完善的管理命令。
  4. 对现有环境无侵入:MHA 只是在现有主从复制基础上增加了一个管理层面,不需要对 MySQL 本身做任何修改。
  5. 支持 GTID 和传统复制:兼容性好。

MHA 的局限性

  1. 需要脚本和 SSH 信任:部署相对复杂,需要配置节点间的 SSH 免密登录。
  2. 单点 Manager:MHA Manager 本身是单点,需要额外的手段来保证其高可用(比如部署备用 Manager 或使用 Keepalived)。
  3. 自愈能力有限:通常不提供自动将旧主库重新拉回集群的功能,需要管理员手动处理。

二、搭建MHA

实验思路:
1.MHA架构
1)数据库安装
2)一主两从
3)MHA搭建

2.故障模拟
1)主库失效
2)备选主库成为主库
3)原故障主库恢复重新加入到MHA成为从库

架构图

1.环境准备

节点服务器 所需服务及组件 IP地址 主机名

角色安装组件IP地址主机名
MHA manager安装MHA node 和 manager 组件192.168.4.54host54
Master安装mysql5.7、MHA node 组件192.168.4.51host51
Slave1安装mysql5.7、MHA node 组件192.168.4.52host52
Slave2安装mysql5.7、MHA node 组件192.168.4.53host53

关闭防火墙,selinux

systemctl stop firewalld
systemctl disable firewalld
setenforce 0

2.配置主机名和 Hosts 解析

分别编辑主机名

hostnamectl set-hostname host51 #4.51主机上执行
hostnamectl set-hostname host52 #4.52主机上执行
hostnamectl set-hostname host53 #4.53主机上执行
hostnamectl set-hostname host54 #4.54主机上执行

编辑所有节点的 /etc/hosts 文件,添加以下内容

echo "192.168.4.51 host51" >> /etc/hosts
echo "192.168.4.52 host52" >> /etc/hosts
echo "192.168.4.53 host53" >> /etc/hosts
echo "192.168.4.54 host54" >> /etc/hosts

3.在所有数据库节点安装MySQL

示范在host51节点安装,另外两个节点同理

    [root@host51 ~]# tar -xvf mysql-5.7.17.tar   #v:显示详细信息
    [root@host51 ~]# yum -y install mysql-community-*.rpm
    [root@host51 ~]# systemctl restart mysqld         #启动服务
    [root@host51 ~]# systemctl enable mysqld
    [root@host51 ~]# ss -antlp | grep 3306
    [root@host51 ~]# ps -C mysqld         #查看进程

连接数据库
使用初始密码登录

    [root@host51 ~]# grep password /var/log/mysqld.log   #获取初始密码
    #重置密码
    [root@host51 ~]# mysqladmin -uroot -p'qg1wpZ;G+deg' password '123qqq...A'   
    [root@host51 ~]# mysql -uroot -p123qqq...A

4.配置 SSH 免密登录

在 MHA Manager 节点上生成密钥对,并分发到所有 MySQL 节点。

[root@host54 ~]# ssh-keygen -f /root/.ssh/id_rsa -N ''
[root@host54 ~]# ssh-copy-id root@host51
[root@host54 ~]# ssh-copy-id root@host52
[root@host54 ~]# ssh-copy-id root@host53

MHA Manager 需要通过 SSH 连接到所有 MySQL 节点执行管理命令(如启动、停止、复制状态检查等),免密登录是必须的。

数据库节点之间也必须配置 SSH 免密码登录,这是 MHA 正常工作的关键要求。

[root@host51 ~]# ssh-keygen -f /root/.ssh/id_rsa -N ''
[root@host51 ~]# ssh-copy-id root@host52
[root@host51 ~]# ssh-copy-id root@host53
[root@host52 ~]# ssh-keygen -f /root/.ssh/id_rsa -N ''
[root@host52 ~]# ssh-copy-id root@host51
[root@host52 ~]# ssh-copy-id root@host53
[root@host53 ~]# ssh-keygen -f /root/.ssh/id_rsa -N ''
[root@host53 ~]# ssh-copy-id root@host51
[root@host53 ~]# ssh-copy-id root@host52

5.配置 MySQL Master 节点

1)修改 MySQL 配置文件 /etc/my.cnf

在mysqld下添加两行

[mysqld]
server_id=51
log_bin=master51
relay-log-purge = 0  # 禁止自动删除中继日志(控制是否自动删除不再需要的中继日志)

重启mysqld服务

systemctl restart mysqld

2)创建授权用户

mysql> grant replication slave on *.* to repluser@"%" identified by '123qqq...A';
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> show master status;
+-----------------+----------+--------------+------------------+-------------------+
| File            | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-----------------+----------+--------------+------------------+-------------------+
| master51.000001 |      441 |              |                  |                   |
+-----------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

6.配置 MySQL Slave 节点 (host52 & host53)

1)修改 MySQL 配置文件 /etc/my.cnf:

在mysqld下添加server_id
host52:

[mysqld]
server_id=52
log_bin=master52
relay-log-purge = 0  # 禁止自动删除中继日志(控制是否自动删除不再需要的中继日志)

host53:

[mysqld]
server_id=53
log_bin=master53
relay-log-purge = 0  # 禁止自动删除中继日志(控制是否自动删除不再需要的中继日志)

重启mysqld服务

[root@host52 ~]# systemctl restart mysqld
[root@host53 ~]# systemctl restart mysqld

2)指定主服务器信息并启动slave

host52:

mysql> change master to master_host='192.168.4.51',master_user='repluser',master_password='123qqq...A',master_log_file='master51.000001',master_log_pos=441;
Query OK, 0 rows affected, 2 warnings (0.02 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.4.51
                  Master_User: repluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master51.000001
          Read_Master_Log_Pos: 441
               Relay_Log_File: host52-relay-bin.000002
                Relay_Log_Pos: 319
        Relay_Master_Log_File: master51.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
....................

host53:

mysql> change master to master_host="192.168.4.51",master_user="repluser",master_password="123qqq...A",master_log_file="master51.000001",master_log_pos=441;
Query OK, 0 rows affected, 2 warnings (0.02 sec)
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.4.51
                  Master_User: repluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master51.000001
          Read_Master_Log_Pos: 441
               Relay_Log_File: host53-relay-bin.000002
                Relay_Log_Pos: 319
        Relay_Master_Log_File: master51.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
....................            

在所有slave节点也授权

grant replication slave on *.* to repluser@"%" identified by "123qqq...A";

7.安装 MHA Node

MHA Node 需要在所有 MySQL 数据库节点上安装
MHA Node 是运行在每台 MySQL 服务器上的代理。
mha-node资源包网址:
https://github.com/yoshinorim/mha4mysql-node/releases/download/v0.58/mha4mysql-node-0.58-0.el7.centos.noarch.rpm

# 安装依赖
# 如果 ncftp 不可用,可以跳过
[root@host51 mysql]# yum -y install perl-DBD-MySQL ncftp perl-DBIx-Simple
[root@host52 mysql]# yum -y install perl-DBD-MySQL nfctp perl-DBIx-Simple
[root@host53 mysql]# yum -y install perl-DBD-MySQL nfctp perl-DBIx-Simple
# 使用 Yum 安装 MHA Node
[root@host51 mysql]# yum -y install mha4mysql-node-0.58-0.el7.centos.noarch.rpm
[root@host52 mysql]# yum -y install mha4mysql-node-0.58-0.el7.centos.noarch.rpm
[root@host53 mysql]# yum -y install mha4mysql-node-0.58-0.el7.centos.noarch.rpm

MHA Node 包含了 save_binary_logs, apply_diff_relay_logs 等关键脚本,用于故障切换时保存和应用日志。

8.在Manager节点上启用epel仓库:

为什么需要 EPEL?
perl-Parallel-ForkManager、perl-Config-IniFiles、ncftp 这些包在 CentOS 默认仓库中不可用
EPEL 仓库提供了这些额外的软件包
先启用 EPEL 可以避免 “No package available” 错误

注意!下载epel仓库需要联网,可以给manage节点设置双网卡,其中一个网卡设置为NAT模式
下载 EPEL 的 RPM 包
EPEL 的官方地址可能会变,但你可以去这个链接下载最新的适用于 CentOS 7 的 EPEL 包:
安装包下载:https://pan.quark.cn/s/956399e9b728

启用 EPEL 仓库
yum -y install epel-release-latest-7.noarch.rpm
yum clean all
yum repolist

9.安装 MHA Manager

仅在 mha-manager 节点上执行
MHA Manager 是管理核心。
mha-manager资源包网址:
https://github.com/yoshinorim/mha4mysql-node/releases/download/v0.58/mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
mha-node资源包网址:
https://github.com/yoshinorim/mha4mysql-node/releases/download/v0.58/mha4mysql-node-0.58-0.el7.centos.noarch.rpm

# 安装依赖
yum install -y perl-DBD-MySQL perl-Config-IniFiles perl-Time-HiRes perl-Parallel-ForkManager ncftp perl-Log-Dispatch perl-DBI mha4mysql-node-0.58-0.el7.centos.noarch.rpm
yum -y install mha4mysql-manager-0.58-0.el7.centos.noarch.rpm

Manager 会监控 Node 的状态,并在 Master 故障时协调故障切换过程

10.配置 MHA

创建 MHA 工作目录和配置文件
在 mha-manager 节点上操作。

mkdir -p /etc/mha
mkdir -p /var/log/mha

创建主配置文件 /etc/mha/app1.cnf:

[server default]
# [server default] 段 - 全局默认配置
# MySQL 用户和密码
# MHA Manager 连接 MySQL 节点时使用的用户名和密码
# 需要在所有 MySQL 节点上创建这个用户并授予相应权限
user=mha
password=123qqq...A
# MySQL 主从复制使用的用户名和密码
# 用于在故障切换时在新主库上配置复制关系
repl_user=repluser
repl_password=123qqq...A
# SSH 配置
ssh_user=root
# MHA Manager 工作目录
manager_workdir=/var/log/mha
manager_log=/var/log/mha/manager.log
# 远程工作目录(在 MySQL 节点上)
remote_workdir=/var/log/mha
# 主从复制相关配置
ping_interval=3
# 二次检查,防止脑裂
secondary_check_script=masterha_secondary_check -s host52 -s host53 -s host51
master_binlog_dir=/var/lib/mysql
# 故障切换脚本(可选)
#master_ip_failover_script=/etc/mha/master_ip_failover
[server1]
hostname=host51
candidate_master=1
[server2]
hostname=host52
candidate_master=1
[server3]
hostname=host53
no_master=1 # 这个节点永远不会被提升为新的 Master

解释:
[server default]:全局默认配置。
secondary_check_script:非常重要,通过多个 Slave 来确认 Master 是否真的宕机,防止网络分区导致的脑裂。
candidate_master=1:优先级高,在故障切换时优先被提升为新主。
no_master=1:标记该节点不应被提升为主库(例如,配置较低或用于备份)。

在master主库授权mha用户

mysql> grant all on *.* to mha@"%" identified by '123qqq...A';
Query OK, 0 rows affected, 1 warning (0.03 sec)

11.检查 MHA 配置

# 检查 SSH 连接
masterha_check_ssh --conf=/etc/mha/app1.cnf
# 检查主从复制状态
masterha_check_repl --conf=/etc/mha/app1.cnf

12.启动 MHA Manager

mkdir -p /var/log/mha
nohup masterha_manager --conf=/etc/mha/app1.cnf < /dev/null > /var/log/mha/manager.log 2>&1 &

13.检查 MHA 状态

[root@host54 ~]# masterha_check_status --conf=/etc/mha/app1.cnf
app1 (pid:12835) is running(0:PING_OK), master:host51

14.故障切换流程(无 VIP 版本)

自动切换过程
MHA 检测到 Master 宕机
自动选择最优 Slave(host52)提升为新 Master
其他 Slave(host53)重新指向新 Master
MHA Manager 记录切换日志并自动停止

1)手动宕机master

停止 host51 的 MySQL 服务

在master节点执行
systemctl stop mysqld

2)查看管理节点日志

在 host54 上验证
[root@host54 ~]# tail -f /var/log/mha/manager.log
Started automated(non-interactive) failover.
The latest slave host52(192.168.4.52:3306) has all relay logs for recovery.
Selected host52(192.168.4.52:3306) as a new master.
host52(192.168.4.52:3306): OK: Applying all logs succeeded.
host53(192.168.4.53:3306): This host has the latest relay log events.
Generating relay diff files from the latest slave succeeded.
host53(192.168.4.53:3306): OK: Applying all logs succeeded. Slave started, replicating from host52(192.168.4.52:3306)
host52(192.168.4.52:3306): Resetting slave info succeeded.
Master failover to host52(192.168.4.52:3306) completed successfully.

3)检查新主库状态

[root@host53 mysql]# mysql -h host52 -u mha -p123qqq...A -e "show master status"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----------------+----------+--------------+------------------+-------------------+
| File            | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-----------------+----------+--------------+------------------+-------------------+
| master52.000001 |      441 |              |                  |                   |
+-----------------+----------+--------------+------------------+-------------------+

4)检查从库复制状态

[root@host52 mysql]# mysql -h host53 -u mha -p123qqq...A -e "show slave status\G"
mysql: [Warning] Using a password on the command line interface can be insecure.
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.4.52
                  Master_User: repluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master52.000001
          Read_Master_Log_Pos: 441
               Relay_Log_File: host53-relay-bin.000002
                Relay_Log_Pos: 319
        Relay_Master_Log_File: master52.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
..............................        

5)插入数据测试验证

在新主库 host52 上插入数据

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |                |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)
mysql> create database d2;
Query OK, 1 row affected (0.02 sec)
mysql> create table d2.student(name char(10),number int default 10);
Query OK, 0 rows affected (0.02 sec)
mysql> insert into d2.student values("bob",1);
Query OK, 1 row affected (0.01 sec)

在从库 host53 上验证数据同步

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |                |
| d2                 |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
6 rows in set (0.00 sec)
mysql> select * from d2.student;
+------+--------+
| name | number |
+------+--------+
| bob  |      1 |
+------+--------+
1 row in set (0.00 sec)

6)恢复旧 Master

因为在host51宕机期间,现在的master节点插入了数据,它们之间有数据差异,所以这里需要先同步数据
备份数据

[root@host52 ~]# mysqldump -uroot -p123456 --all-databases --master-data=1 > backup.sql
[root@host52 ~]# scp backup.sql host51:/root/

host51同步数据

[root@host51 ~]# systemctl start mysqld
[root@host51 ~]# mysql -uroot -p123456 < backup.sql 
[root@host51 ~]# mysql -uroot -p123456
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |               |
| d2                 |               |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
7 rows in set (0.00 sec)
mysql> select * from d2.student;
+------+--------+
| name | number |
+------+--------+
| bob  |      1 |
+------+--------+
1 row in set (0.00 sec)

查看当前master host52的status

mysql> show master status;
+-----------------+----------+--------------+------------------+-------------------+
| File            | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-----------------+----------+--------------+------------------+-------------------+
| master52.000001 |     1046 |              |                  |                   |
+-----------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

host51配置为当前 Master 的从库:

-- 在旧 Master 上执行
mysql> change master to master_host="192.168.4.52", master_user="repluser", master_password="123qqq...A", master_log_file="master52.000001", master_log_pos=1046;
Query OK, 0 rows affected, 2 warnings (0.01 sec)
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.4.52
                  Master_User: repluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master52.000001
          Read_Master_Log_Pos: 1046
               Relay_Log_File: host51-relay-bin.000002
                Relay_Log_Pos: 319
        Relay_Master_Log_File: master52.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

7)验证旧master

在host52上插入数据

mysql> create database d3;
Query OK, 1 row affected (0.01 sec)
mysql> create table d3.student(name char(10),number int default 10);
Query OK, 0 rows affected (0.02 sec)
mysql> insert into d3.student values("tom",2);
Query OK, 1 row affected (0.00 sec)

在host51上检查数据

mysql> select * from d3.student;
+------+--------+
| name | number |
+------+--------+
| tom  |      2 |
+------+--------+
1 row in set (0.01 sec)

到此,mha高可用集群搭建完毕

到此这篇关于MySQL MHA 高可用集群搭建指南的文章就介绍到这了,更多相关MySQL MHA 高可用集群内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文