本教程接上篇mysql高可用架构之MHA部署(一)(保姆级),手动模拟故障后,再次将故障节点加入主从架构,并且实现主节点IP漂移
1、故障节点加入主从架构
由于MHA运行结束后,mysql主从架构发生了改变,主节点已经由之前的【10.0.0.60】变为【10.0.0.61】,要想再次恢复到一主两从的架构,需要手动将
【10.0.0.60】作为从节点加入到里面,下面开始操作
【10.0.0.60】执行:
- 停止复制进程并重置
sql
mysql> stop slave;
mysql> reset slave all;
- 从库重新chage master to,主库改成10.0.0.61
sql
mysql> CHANGE MASTER TO
MASTER_HOST='10.0.0.61',
MASTER_USER='repl',
MASTER_PASSWORD='2544',
MASTER_AUTO_POSITION=1;
- 开启线程:
sql
mysql> start slave;
- 查看主从复制状态正常
sql
mysql> show slave status\G

可以看到10.0.0.60作为从库,10.0.0.61作为主库
2、修改MHA配置文件,使之适配修改后的主从架构
由于主从架构有变,之前的从变成了主,所以配置文件也需要做修改,使得MHA能再次使用
bash
vim /etc/mha/mysql_cluster.cnf
我们会发现这里没有最初的[server1]的配置了,这是由于MHA实现了故障切换,会从配置文件踢掉故障的节点,我们需要修改的是将[server1]加进去,并且指定[server1]作为下一次故障后的主节点

修改后的配置,需要注意的是加入[server1]后,额外添加candidate_master=1
指定下次故障后[server1]作为主节点,并注释掉[server2]里面的candidate_master=1
3、检查MHA的可用性、验证集群状态
- 检查MHA复制健康状态(确保所有节点正常)
bash
masterha_check_repl --conf=/etc/mha/mysql_cluster.cnf
返回值为:MySQL Replication Health is OK.
- 检查 SSH 免密登录
bash
masterha_check_ssh --conf=/etc/mha/mysql_cluster.cnf
返回值为:All SSH connection tests passed successfully.
- 重启MHA Manager服务(使配置生效)
bash
nohup masterha_manager --conf=/etc/mha/mysql_cluster.cnf --remove_dead_master_conf --ignore_laster_failover > /var/log/mha/mysql_cluster/manager.log 2>&1 &
- 确认MHA状态
bash
masterha_check_status --conf=/etc/mha/mysql_cluster.cnf
#正常输出应为:mysql_cluster (pid: xxxx) is running(0:PING_OK)
这里返回值为:
mysql_cluster (pid:4063) is running(0:PING_OK), master:10.0.0.61
- 删除mysql_cluster.failover.complete
bash
cd /var/log/mha/mysql_cluster/
rm -rf mysql_cluster.failover.complete
mysql_cluster.failover.complete 作为故障转移完成的标志:供管理员或脚本判断 "上一次故障转移是否成功结束"。当 MHA 完成一次故障转移后,会在 管理节点的工作目录(通常是 --manager_workdir 指定的路径,MHA管理节点mha manger 配置文件里面写了
去该路径下删除即可
4、应用透明
在讨论 "MHA 应用透明(VIP)" 时,首先需要结合 "MHA" 的常见场景定义 ------ 其最广泛的指向是 MySQL High Availability(MySQL 高可用)解决方案,核心用于保障 MySQL 数据库集群的稳定性、故障自动切换与数据一致性,而 "透明(VIP)" 则通常关联 "虚拟 IP(Virtual IP,简称 VIP)"技术,是实现 MHA 高可用 "透明化" 的关键组件。以下从核心概念、实现逻辑、VIP 的核心作用及典型应用场景展开说明,帮你全面理解这一技术组合:
4.1 核心概念:MHA 与 "透明(VIP)" 的关联
MHA(MySQL High Availability)是一套开源的 MySQL 高可用架构方案,由 "MHA Manager(管理节点)" 和 "MHA Node(数据节点,部署在每个 MySQL 服务器上)" 组成,核心能力是:
- 实时监控 MySQL 主从集群的健康状态(如主库宕机、网络中断);
- 故障发生时自动完成 "主库切换"(从多个从库中选最优从库升级为主库);
- 最小化数据丢失(通过 binlog 补传等机制)。
- "透明(VIP)" 的核心:虚拟 IP(VIP)技术 "透明" 在这里的核心含义是 "对应用层无感知" ------ 即 MySQL 集群发生主从切换后,应用程序无需修改数据库连接地址(IP),仍能正常访问新的主库。而实现这一 "透明性" 的关键就是VIP:
- VIP 是一个 "逻辑 IP 地址",不绑定到具体的物理服务器网卡,而是动态绑定到当前的 MySQL 主库服务器上。应用程序始终连接 VIP,当主库故障、MHA 切换新主库后,MHA 会自动将 VIP 从旧主库 "漂移" 到新主库,从而实现应用访问的无缝衔接。
5.2 MHA+VIP 实现 "应用透明" 的核心逻辑(步骤)
以典型的 "1 主 2 从" MySQL 集群为例,MHA+VIP 的工作流程如下,全程对应用无感知:
- 正常状态:VIP 绑定主库
初始时,MySQL 主库(如服务器 A)正常运行,MHA Manager 将 VIP(如192.168.1.100)绑定到服务器 A 的网卡上;应用程序的数据库连接地址配置为 VIP(192.168.1.100),所有读写请求通过 VIP 路由到主库 A。 - 故障触发:主库宕机,MHA 检测并选新主
若主库 A 因硬件故障、网络中断等宕机,MHA Node 会向 MHA Manager 上报故障;MHA Manager 通过 "日志完整性、从库延迟、服务器配置" 等指标,从 2 个从库(如服务器 B、C)中选择最优节点(如 B)作为新主库。 - VIP 漂移:实现应用透明切换
MHA Manager 自动执行 "VIP 漂移" 操作:先解除旧主库 A 的 VIP 绑定(若 A 仍存活则强制解绑),再将 VIP 绑定到新主库 B 的网卡;整个漂移过程通常在秒级完成(取决于 MHA 配置的检测间隔),应用程序的数据库连接无需修改,仍通过 VIP(192.168.1.100)访问,此时请求会自动路由到新主库 B,实现 "无感知切换"。 - 恢复后:旧主库归位,VIP 保持在新主
旧主库 A 修复后,MHA 会将其自动配置为新主库 B 的从库(同步新主库数据),VIP 则保持绑定在新主库 B 上,避免再次切换影响应用。
5.3 VIP 在 MHA "应用透明" 中的 3 个核心作用

5.4 典型应用场景(适合用 MHA+VIP 的场景)
- 对数据库可用性要求高的业务:如电商交易、金融支付、实时订单系统,需避免因 MySQL 故障导致业务中断;
- 应用层不支持 "多主库地址配置" 的场景:部分老旧应用或第三方系统仅支持单数据库 IP 配置,无法通过应用层实现主从切换,需依赖 VIP 实现透明访问;
- 中小规模 MySQL 集群:MHA+VIP 架构轻量、开源(无额外 license 成本),适合 10 节点以内的 MySQL 主从集群,运维成本较低。
5.5 注意事项(避免 "透明性" 失效的关键)
- VIP 漂移的网络权限:MHA Manager 需要拥有 "修改各 MySQL 节点网卡 IP" 的权限(如 root 权限),否则无法执行 VIP 绑定 / 解绑操作;
- 避免 VIP 冲突:VIP 需与 MySQL 集群在同一网段,且不能与其他服务器的物理 IP 重复,否则会导致网络冲突;
- 双 VIP 配置(可选):若需区分 "读请求" 和 "写请求",可配置两个 VIP (写 VIP 绑定主库,读 VIP 绑定从库),进一步优化读写分离的透明性;
- 监控 VIP 状态:需额外监控 VIP 的绑定状态(如通过 Zabbix、Prometheus),避免因 MHA 故障导致 VIP 未漂移,引发 "应用连不上库" 的隐性问题。
如果你的 "MHA" 指向其他领域(如特定行业的系统、软件缩写),可以补充说明具体场景
根据需求,我设计了一个仅在 Manager 节点部署的脚本,它会使用你在主库手工配置的 VIP,实现 MHA 的 VIP 透明切换功能。这个脚本会将预设的 VIP 信息写入配置,并在故障发生时自动将 VIP 从旧主库迁移到新主库。
bash
vim /usr/local/bin/master_ip_failover.sh
#!/bin/bash
# 脚本用途:MHA master_ip_failover_script 专用(兼容状态检查和故障切换)
# 支持两种参数模式:
# 1. 状态检查:--command=status --orig_master_ip=xxx --orig_master_port=xxx...
# 2. 故障切换:start/stop 旧主IP 旧主端口 新主IP 新主端口 MHA节点IP
# -------------------------- 配置区(修改为你的环境)--------------------------
VIP="10.0.0.55" # VIP地址
NETMASK="24" # 子网掩码
VIRTUAL_INTERFACE="ens33:1" # 虚拟接口
SSH_USER="root" # SSH免密用户
LOG_FILE="/var/log/mha/vip_failover.log" # 日志路径
# ---------------------------------------------------------------------------------
# 确保日志目录存在
[ -d $(dirname $LOG_FILE) ] || mkdir -p $(dirname $LOG_FILE)
# -------------------------- 工具函数 --------------------------
log() {
local log_time=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$log_time] $1" >> $LOG_FILE
echo "[$log_time] $1"
}
# SSH执行命令
ssh_exec() {
local host="$1"
local cmd="$2"
ssh -o BatchMode=yes -o ConnectTimeout=5 "$SSH_USER@$host" "$cmd" > /dev/null 2>&1
return $?
}
# -------------------------- VIP操作函数 --------------------------
# 添加VIP
vip_add() {
local host="$1"
local vip_full="$VIP/$NETMASK"
log "在 $host 添加VIP:$vip_full(接口:$VIRTUAL_INTERFACE)"
ssh_exec "$host" "ifconfig $VIRTUAL_INTERFACE $vip_full up"
sleep 3
ssh_exec "$host" "ifconfig $VIRTUAL_INTERFACE 2>/dev/null | grep -q '$VIP'"
if [ $? -eq 0 ]; then
log "$host VIP添加成功"
return 0
else
log "$host VIP添加失败"
return 1
fi
}
# 移除VIP
vip_remove() {
local host="$1"
log "从 $host 移除VIP:$VIP(接口:$VIRTUAL_INTERFACE)"
ssh_exec "$host" "ifconfig $VIRTUAL_INTERFACE down"
sleep 2
ssh_exec "$host" "ifconfig $VIRTUAL_INTERFACE 2>/dev/null | grep -q '$VIP'"
if [ $? -ne 0 ]; then
log "$host VIP移除成功"
return 0
else
log "$host VIP移除失败(可能已宕机)"
return 0
fi
}
# 检查VIP状态(供status命令使用)
vip_check_status() {
local host="$1"
ssh_exec "$host" "ifconfig $VIRTUAL_INTERFACE 2>/dev/null | grep -q '$VIP'"
if [ $? -eq 0 ]; then
log "VIP在 $host 上存在"
return 0
else
log "VIP在 $host 上不存在"
return 1
fi
}
# -------------------------- 参数解析与处理 --------------------------
# 解析键值对参数(状态检查时使用)
# 解析键值对参数(状态检查时使用)
# 解析键值对参数(MHA触发的status/stopssh/start/stop命令均在此处理)
parse_key_value_params() {
local command=""
local orig_master_ip="" # 旧主库IP(stop命令用)
local new_master_ip="" # 新主库IP(start命令用)
local orig_master_port=""
local new_master_port=""
# 1. 提取所有键值对参数(包括start/stop命令需要的新/旧主库IP)
for param in "$@"; do
case "$param" in
--command=*) command="${param#*=}" ;;
--orig_master_ip=*) orig_master_ip="${param#*=}" ;; # 旧主库IP(stop命令用)
--new_master_ip=*) new_master_ip="${param#*=}" ;; # 新主库IP(start命令用)
--orig_master_port=*) orig_master_port="${param#*=}" ;;
--new_master_port=*) new_master_port="${param#*=}" ;;
esac
done
# 2. 处理MHA触发的4种核心命令
case "$command" in
# 命令1:status(检查主库VIP状态)
status)
log "收到status命令,检查主库 $orig_master_ip 的VIP状态"
[ -z "$orig_master_ip" ] && { log "错误:缺少orig_master_ip参数"; return 1; }
vip_check_status "$orig_master_ip"
return $?
;;
# 命令2:stopssh(释放旧主库SSH连接,无需实际操作)
stopssh)
log "收到stopssh命令,释放旧主库 $orig_master_ip 的SSH连接(无需操作)"
return 0
;;
# 命令3:stop(从旧主库删除VIP)
stop)
log "收到stop命令,从旧主库 $orig_master_ip 移除VIP"
[ -z "$orig_master_ip" ] && { log "错误:缺少orig_master_ip参数"; return 1; }
vip_remove "$orig_master_ip" # 复用已有的VIP删除函数
return $?
;;
# 命令4:start(在新主库添加VIP)
start)
log "收到start命令,在新主库 $new_master_ip 添加VIP"
[ -z "$new_master_ip" ] && { log "错误:缺少new_master_ip参数"; return 1; }
vip_add "$new_master_ip" # 复用已有的VIP添加函数
return $?
;;
# 不支持的命令
*)
log "不支持的命令:$command"
return 1
;;
esac
}
# 处理位置参数(故障切换时使用)
handle_position_params() {
local operation="$1"
local old_master_ip="$2"
local old_master_port="$3"
local new_master_ip="$4"
local new_master_port="$5"
# local mha_ip="$6" # 第6个参数暂不使用
case "$operation" in
start)
log "收到start命令,在新主库 $new_master_ip 添加VIP"
[ -z "$new_master_ip" ] && { log "错误:新主库IP为空"; return 1; }
vip_add "$new_master_ip"
;;
stop)
log "收到stop命令,从旧主库 $old_master_ip 移除VIP"
[ -z "$old_master_ip" ] && { log "错误:旧主库IP为空"; return 1; }
vip_remove "$old_master_ip"
;;
release)
log "收到release命令,无需操作"
return 0
;;
*)
log "不支持的操作:$operation"
return 1
;;
esac
}
# -------------------------- 脚本入口 --------------------------
log "===== 脚本启动,参数总数:$# ====="
log "参数列表:$*"
# 区分参数模式:键值对参数(含--command)还是位置参数
if [[ "$*" == *--command=* ]]; then
# 处理状态检查的键值对参数
parse_key_value_params "$@"
else
# 处理故障切换的位置参数(兼容5或6个参数)
if [ $# -eq 5 ] || [ $# -eq 6 ]; then
handle_position_params "$1" "$2" "$3" "$4" "$5" "$6"
else
log "错误:位置参数数量不正确(实际$#个,需5或6个)"
exit 1
fi
fi
log "===== 脚本执行结束 ====="
exit 0
脚本使用说明
这个脚本完全符合需求:
1、仅在 MHA Manager 节点部署
2、使用你预先在主库手工配置的 VIP(通过ifconfig ens33:1 10.0.0.55/24)
3、实现 VIP 透明切换功能,应用无需感知数据库主从切换
配置步骤
首先在主库手工配置 VIP(这是你的要求):
#在MySQL主库服务器上执行
bash
ifconfig ens33:1 10.0.0.55/24 up
[root@mysql_0 ~]# ifconfig ens33:1 10.0.0.55/24
[root@mysql_0 ~]# ifconfig ens33:1 10.0.0.55/24 up
这里会出现子ip
bash
vim /usr/local/bin/master_ip_failover.sh
在 Manager 节点配置脚本:
复制上述脚本到 MHA Manager 节点(如/usr/local/bin/目录,修改脚本顶部的配置区域,确保与你的环境一致:
bash
VIP="10.0.0.55" # 与你手工配置的VIP一致
NETMASK="24" # 子网掩码
INTERFACE="ens33" # 主库物理网卡
VIRTUAL_INTERFACE="ens33:1" # 虚拟接口,与手工配置一致
SSH_USER="root" # 具有免密登录权限的用户
MHA_CONF="/etc/mha/mysql_cluster.cnf" # MHA配置文件路径
赋予执行权限:
bash
chmod +x /usr/local/bin/master_ip_failover.sh
要让 MHA 在检测到主库故障并完成切换后自动调用此脚本迁移 VIP,需要修改 MHA 配置文件:
bash
[server default]
#其他配置...
master_ip_failover_script=/usr/local/bin/master_ip_failover.sh
例如:
这样,当 MHA 执行故障切换时,会自动调用脚本将 VIP 从旧主库迁移到新主库,实现对应用的透明性。
脚本核心功能
使用这个脚本后,应用程序只需连接 VIP(10.0.0.55),无论 MHA 何时进行主从切换,应用都无需修改配置,实现了真正的透明访问。
6、修改完配置文件,需要重新运行MHA程序
- 1、MHA 启动
bash
nohup masterha_manager --conf=/etc/mha/mysql_cluster.cnf --remove_dead_master_conf --ignore_laster_failover > /var/log/mha/mysql_cluster/manager.log 2>&1 &
- 2、MHA 停止
bash
masterha_stop --conf=/etc/mha/mysql_cluster.cnf
- 3、检查 MHA 状态
bash
masterha_check_status --conf=/etc/mha/mysql_cluster.cnf
- 4、检查 SSH 免密登录
bash
masterha_check_ssh --conf=/etc/mha/mysql_cluster.cnf
- 5、检查主从复制
bash
masterha_check_repl --conf=/etc/mha/mysql_cluster.cnf
这里就可以看到主从架构、以及VIP在哪台服务器
7、停掉主库mysql(模拟mysql故障)、在主库服务器执行
bash
systemctl stop mysqld
- 1、删除报错文件(如果有)
bash
rm -f /var/log/mha/mysql_cluster/mysql_cluster.failover.error
- 2、观测VIP脚本日志
bash
tail -f /var/log/mha/vip_failover.log

可以看到VIP由原主库【10.0.0.61】变到新主库【10.0.0.60】上了
在【10.0.0.60】查看VIP信息,确实有了
- 3、查看MHA日志
bash
vim /var/log/mha/mysql_cluster/manager.log

可以看到当旧主库【10.0.0.61】宕掉之后,新的主库【10.0.0.60】顶替了。
VIP漂移也实现了。主库切为【10.0.0.60】了
至此,我们实现了MHA高可用,并且实现了应用透明(VIP),浮动IP漂移
,后面在第三篇我也会进行MHA邮箱告警的配置。