MySQL高可用(MHA)
什么是MHA
MHA(Master High Availability)是一套针对MySQL的高可用解决方案,能实现自动故障检测与主从切换,有效减少MySQL故障恢复时间,提高服务可用性。
其核心特点包括:
自动故障检测与切换:通过定期监控主库状态,当主库出现故障(如宕机、网络中断等)时,能自动识别并在从库中选择最合适的节点提升为新主库,整个过程无需人工干预。
数据一致性保障:在切换过程中,会尽量复制主库未同步到从库的binlog日志,最大程度减少数据丢失;支持GTID(全局事务标识),简化binlog定位与同步流程。
灵活的候选主库选择:可通过配置指定优先成为新主库的候选节点,优先选择数据最新、负载较低的从库,确保切换后服务稳定。
低性能损耗:监控过程对MySQL集群性能影响极小,仅通过SSH和MySQL账号进行轻量通信。
架构简洁:由Manager(管理节点)和Node(数据节点代理)两部分组成,Manager负责监控和决策,Node部署在所有MySQL节点上执行具体操作(如复制管理、binlog处理等)。
MHA适用于一主多从的MySQL架构,广泛应用于需要高可用保障的生产环境,尤其适合对数据库 downtime 敏感的业务场景。不过需要注意的是,它本身不提供负载均衡功能,通常需与其他工具(如ProxySQL、HAProxy)配合使用以实现读写分离和流量切换。
MHA实现原理
(1)从宕机崩溃的master保存二进制日志事件(binlog events);
(2)识别含有最新更新的slave;
(3)应用差异的中继日志(relay log)到其他的slave;
(4)应用从master保存的二进制日志事件(binlog events);
(5)提升一个slave为新的master;
(6)使其他的slave连接新的master进行复制;
MHA搭建流程
要搭建MHA,要求一个复制集群中必须最少有三台数据库服务器,一主二从,即一台master,一台充当备用master,另外一台充当从库。
MHA Manager会定时探测集群中的master节点,当master出现故障时,它可以自动将最新数据的slave提升为新的master,然后将所有其他的slave重新指向新的master,整个故障转移过程对应用程序完全透明。
环境准备
服务器规划(至少3节点)
MHA管理节点(独立服务器)实验时根据自身条件可选择性添加
注意
建议:如果没有独立机器,把 Manager 装在从库上(而不是主库),这样主库宕机时 Manager 还能正常工作,不会单点失效。
基础配置(所有节点)3台及4台操作方式
# 关闭防火墙
systemctl stop firewalld && systemctl disable firewalld
# 关闭SELinux
setenforce 0
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
# hosts 配置(所有 3 台机器)
cat >> /etc/hosts << EOF
192.168.7.50 mha-node1
192.168.7.51 mha-node2
192.168.7.52 mha-node3
EOF
# 免密登录(所有 3 台机器分别执行)
## 先在当前机器上生成密钥对
ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa
## 再执行循环复制公钥的命令
for host in mha-node1 mha-node2 mha-node3; do
ssh-copy-id -i ~/.ssh/id_rsa.pub $host
done
## 执行过程中,每台机器会依次提示你输入一次密码
输入正确的 root 密码后,该节点的免密就配置好了,然后会自动继续下一个节点。
# hosts 配置(所有 4 台机器)
cat >> /etc/hosts << EOF
192.168.7.50 mha-manager
192.168.7.51 mha-node1
192.168.7.52 mha-node2
192.168.7.53 mha-node3
EOF
# 免密登录(所有 4 台机器分别执行)
## 先在当前机器上生成密钥对
ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa
## 再执行循环复制公钥的命令
for host in mha-manager mha-node1 mha-node2 mha-node3; do
ssh-copy-id -i ~/.ssh/id_rsa.pub $host
done
## 执行过程中,每台机器会依次提示你输入一次密码
输入正确的 root 密码后,该节点的免密就配置好了,然后会自动继续下一个节点。
# 操作步骤的区别
有独立 MHA Manager(4 台机器)
需要在 4 台机器上分别执行:
机器 执行内容
mha-manager 生成密钥 → 复制公钥到 mha-node1/2/3
mha-node1 生成密钥 → 复制公钥到 mha-node1/2/3(含自己)
mha-node2 生成密钥 → 复制公钥到 mha-node1/2/3(含自己)
mha-node3 生成密钥 → 复制公钥到 mha-node1/2/3(含自己)
没有独立 MHA Manager(3 台机器)
只需在 3 台机器上执行:
机器 执行内容
mha-node1 生成密钥 → 复制公钥到 mha-node1/2/3(含自己)
mha-node2 生成密钥 → 复制公钥到 mha-node1/2/3(含自己)
mha-node3 生成密钥 → 复制公钥到 mha-node1/2/3(含自己)
部署MySQL 8.0主从复制
安装MySQL 8.0(所有数据库节点:mha-node1、mha-node2、mha-node3)
安装方式:脚本安装、yum安装、二进制安装等。
根据个人习惯进行安装、或者要求安装;
配置MySQL(主从差异化配置)
Master(mha-node1)配置
# 修改配置文件
vim /etc/my.cnf
[mysqld]
# ...
# 在默认配置下方添加:
server-id=50 # 唯一ID
log_bin=mysql-bin # 开启binlog
binlog_format=ROW # ROW模式(MHA推荐)
gtid_mode=ON # 开启GTID
enforce_gtid_consistency=ON # 强制GTID一致性
log_slave_updates=ON # 从库同步时记录binlog(用于级联复制)
skip_name_resolve=ON # 跳过域名解析
# 重启mysql
systemctl restart mysqldSlave(mha-node2/mha-node3)配置
# 修改配置文件
vim /etc/my.cnf
[mysqld]
# ...
server-id=51 # 唯一ID (mha-node3设为52)
log_bin=mysql-bin
binlog_format=ROW
gtid_mode=ON
enforce_gtid_consistency=ON
log_slave_updates=ON
skip_name_resolve=ON
relay_log=relay-bin # 开启中继日志
read_only=ON # 从库只读(可选)
# 重启mysql
systemctl restart mysqld搭建主从复制(基于GTID)
在Master(mha-node1)创建复制用户
-- MySQL 8.0默认认证插件为caching_sha2_password,MHA需用mysql_native_password
-- 登录Master的MySQL
# 创建复制用户
CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
# 给用户授予权限
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
# 刷新权限
FLUSH PRIVILEGES;在Slave(mha-node2/mha-node3)配置复制
-- 登录Slave的MySQL
CHANGE MASTER TO
MASTER_HOST='mha-node1',
MASTER_USER='repl',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
MASTER_AUTO_POSITION=1; # 基于GTID自动定位
-- 启动复制
START SLAVE;
-- 检查复制状态(确保Slave_IO_Running和Slave_SQL_Running均为Yes)
SHOW SLAVE STATUS\G;部署MHA
完整安装清单
1. 安装依赖(所有节点)
CentOS7安装依赖
# 配置yum源确保下载依赖无问题
## 配置Yum扩展源
wget -O /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo
# 安装Perl依赖(MHA基于Perl开发)
yum install -y perl-DBD-MySQL perl-CPAN perl-Config-Tiny perl-Log-Dispatch perl-Parallel-ForkManager perl-ExtUtils-CBuilder perl-ExtUtils-MakeMaker
# Perl 模块构建工具
yum install -y perl-Module-Install
# 如需邮件告警(实验环境强烈不推荐安装)(安装位置确定有MHA Manager)
# 1. 先安装 perl-CPAN(麒麟系统)
yum install -y perl-CPAN
# 2. 用 cpan 安装邮件模块
cpan -i Email::Sender Email::Valid Mail::SenderUbuntu22.04安装依赖包
sudo apt install -y perl libdbi-perl libdbd-mysql-perl libperl-dev libconfig-tiny-perl liblog-dispatch-perl 安装MHA包
下载MHA源码包
# github下载(经常连接不上)
# 管理节点下载(只在 Manager 节点(mha-node2)下载)
wget https://github.com/yoshinorim/mha4mysql-manager/releases/download/v0.58/mha4mysql-manager-0.58.tar.gz
# 所有节点下载(所有 3/4 台机器都要下载)
wget https://github.com/yoshinorim/mha4mysql-node/releases/download/v0.58/mha4mysql-node-0.58.tar.gz
# 备选方案(通过代理下载)
# 管理节点下载(只在 Manager 节点(mha-node2)下载)
wget https://ghproxy.net/https://github.com/yoshinorim/mha4mysql-manager/releases/download/v0.58/mha4mysql-manager-0.58.tar.gz
# 所有节点下载(所有 3/4 台机器都要下载)
wget https://ghproxy.net/https://github.com/yoshinorim/mha4mysql-node/releases/download/v0.58/mha4mysql-node-0.58.tar.gz安装MHA Node(所有节点)
# 1. 解压
tar -zxvf mha4mysql-node-0.58.tar.gz
# 2. 进入目录
cd mha4mysql-node-0.58
# 3. 生成编译配置
perl Makefile.PL
# 4. 编译及安装
make && make install
安装MHA Manager(仅manager节点)
# 1. 解压 Manager 源码包
tar -zxvf mha4mysql-manager-0.58.tar.gz
# 2. 进入解压后的目录
cd mha4mysql-manager-0.58
# 3. 生成编译配置文件
perl Makefile.PL
# 4. 编译及安装
make && make install
manager组件安装后在/usr/local/bin下面会生成几个工具,主要包括以下几个:
masterha_check_ssh 检查 MHA 的 SSH 配置状况
masterha_check_repl 检查 MySQL 复制状况
masterha_manger 启动 manager的脚本
masterha_check_status 检测当前 MHA 运行状态
masterha_master_monitor 检测 master 是否宕机
masterha_master_switch 控制故障转移(自动或者手动)
masterha_conf_host 添加或删除配置的 server 信息
masterha_stop 关闭manager
node组件安装后也会在/usr/local/bin 下面会生成几个脚本(这些工具通常由 MHAManager 的脚本触发,无需人为操作)主要如下:
save_binary_logs 保存和复制 master 的二进制日志
apply_diff_relay_logs 识别差异的中继日志事件并将其差异的事件应用于其他的 slave
filter_mysqlbinlog 去除不必要的 ROLLBACK 事件
purge_relay_logs 清除中继日志(Relay-log)
配置MHA
创建MHA配置文件(manager节点)
# manager节点 (mha-node2)
# 创建目录
mkdir -p /etc/mha
# 写入配置文件
cat > /etc/mha/mha_cluster.cnf << EOF
[server default]
# MHA管理用户(需在所有MySQL节点创建)
user=mha_user
password=123456
# SSH登录用户
ssh_user=root
# MySQL复制用户
repl_user=repl
repl_password=123456
# 健康检查间隔(秒)
ping_interval=1
# master的binlog目录
master_binlog_dir=/usr/local/mysql/data
# 远程节点临时目录
remote_workdir=/tmp
# 二次检查节点(根据Manager安装调整检查节点)
secondary_check_script=masterha_secondary_check -s mha-node1 -s mha-node3
# manager工作目录
manager_workdir=/var/log/mha/mha_cluster
# manager日志
manager_log=/var/log/mha/mha_cluster/manager.log
[server1]
hostname=mha-node1
port=3306
# 不优先作为候选主库
candidate_master=0
[server2]
hostname=mha-node2
port=3306
# 优先作为候选主库(数据最新时)
candidate_master=1
# 忽略复制延迟,强制作为候选
check_repl_delay=0
[server3]
hostname=mha-node3
port=3306
candidate_master=0
EOF创建MHA管理用户(主MySQL节点从的会自动同步)
# 创建用户
CREATE USER 'mha_user'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
# 权限设置
GRANT ALL PRIVILEGES ON *.* TO 'mha_user'@'%';
# 刷新配置
FLUSH PRIVILEGES;验证MHA配置
1. 检查SSH连接(manager节点)
masterha_check_ssh --conf=/etc/mha/mha_cluster.cnf
# 输出"All SSH connection tests passed successfully."即为正常2. 检查主从复制(manager节点)
masterha_check_repl --conf=/etc/mha/mha_cluster.cnf
# 输出"MySQL Replication Health is OK."即为正常
# 基本会报错所以需要去修复一下问题
# 原因是MHA 的代码与系统上高版本的 Perl 不完全兼容。修复 Perl 语法错误
编辑NodeUtil.pm
# 编辑配置文件
vim /usr/local/share/perl5/MHA/NodeUtil.pm
# 修改第 195 行
修改前:
my $result = sprintf( '%03d%03d%03d', $str =~ m/(\d+)/g );
修改后:
my @nums = ($str =~ m/(\d+)/g);
my $result = sprintf( '%03d%03d%03d', $nums[0], $nums[1], $nums[2] );
# 修改第 201 行
修改前:
my $result = sprintf( '%03d%03d', $str =~ m/(\d+)/g );
修改后:
my @nums = ($str =~ m/(\d+)/g);
my $result = sprintf( '%03d%03d', $nums[0], $nums[1] );启动MHA Manager
# 前台启动(测试用,日志实时输出)
masterha_manager --conf=/etc/mha/mha_cluster.cnf
# 后台启动(生产用)
nohup masterha_manager --conf=/etc/mha/mha_cluster.cnf > /var/log/mha/mha_cluster/nohup.log 2>&1 &
# 检查MHA状态
masterha_check_status --conf=/etc/mha/mha_cluster.cnf
# 输出"mha_cluster (pid: xxxx) is running(0:PING_OK)"即为正常运行测试故障切换
1. 模拟Master故障(在mha-node1执行)
systemctl stop mysqld # 停止主库服务2. 观察故障切换(manager节点日志)
tail -f /var/log/mha/mha_cluster/manager.log
# 正常情况下,日志会显示:
# - 检测到master故障
# - 提升mha-node2为新master
# - 其他slave(mha-node3)指向新master3. 验证切换结果
# 在新master(mha-node2)查看状态
mysql -uroot -p -e "SELECT @@server_id, @@read_only;"
# 应显示server_id=51,read_only=O
# 在mha-node3查看复制状态
mysql -uroot -p -e "SHOW SLAVE STATUS\G"
# 应显示Master_Host为mha-node2,且复制正常故障恢复后处理
查看当前主库(mha-node2)
# 查看状态
mysql -uroot -p -e "SELECT @@server_id, @@hostname, @@read_only;"
# 预期效果
+-------------+------------+-------------+
| @@server_id | @@hostname | @@read_only |
+-------------+------------+-------------+
| 51 | mha-node2 | 0 |
+-------------+------------+-------------+查看从库(mha-node3)复制状态
# 查看状态
mysql -uroot -p -e "SHOW SLAVE STATUS\G" | grep -E "Master_Host|Slave_IO_Running|Slave_SQL_Running"
# 预期效果
Master_Host: mha-node2
Slave_IO_Running: Yes
Slave_SQL_Running: Yes恢复旧主库(mha-node1)作为从库
获取复制用户密码
# 在mha-node2上查看配置文件
grep -i "repl_password" /etc/mha/mha_cluster.cnf
# 或在MySQL中重置密码(如果不知道)
mysql -uroot -p -e "ALTER USER 'repl'@'%' IDENTIFIED BY '123456';"在mha-node1上配置复制MySQL里面
STOP SLAVE;
RESET SLAVE ALL;
CHANGE MASTER TO
MASTER_HOST='192.168.7.51',
MASTER_PORT=3306,
MASTER_USER='repl',
MASTER_PASSWORD='123456',
MASTER_AUTO_POSITION=1;
START SLAVE;完成后回到 mha-node2,继续后续步骤
清理故障标记文件
rm -f /var/log/mha/mha_cluster/mha_cluster.failover.complete验证复制状态
masterha_check_repl --conf=/etc/mha/mha_cluster.cnf重启MHA Manager
nohup masterha_manager --conf=/etc/mha/mha_cluster.cnf > /var/log/mha/mha_cluster/nohup.log 2>&1 &确认运行状态
masterha_check_status --conf=/etc/mha/mha_cluster.cnfMySQL高可用(MHA)
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法