mysql高可用架构之MHA部署(二)VIP漂移(保姆级)
本教程接上篇mysql高可用架构之MHA部署(一)(保姆级),手动模拟故障后,再次将故障节点加入主从架构,并且实现主节点IP漂移
1、故障节点加入主从架构
由于MHA运行结束后,mysql主从架构发生了改变,主节点已经由之前的【10.0.0.60】变为【10.0.0.61】,要想再次恢复到一主两从的架构,需要手动将
【10.0.0.60】作为从节点加入到里面,下面开始操作
【10.0.0.60】执行:
- 停止复制进程并重置
mysql> stop slave;
mysql> reset slave all;
- 从库重新chage master to,主库改成10.0.0.61
mysql> CHANGE MASTER TOMASTER_HOST='10.0.0.61',MASTER_USER='repl',MASTER_PASSWORD='2544',
MASTER_AUTO_POSITION=1;
- 开启线程:
mysql> start slave;
- 查看主从复制状态正常
mysql> show slave status\G
可以看到10.0.0.60作为从库,10.0.0.61作为主库
2、修改MHA配置文件,使之适配修改后的主从架构
由于主从架构有变,之前的从变成了主,所以配置文件也需要做修改,使得MHA能再次使用
vim /etc/mha/mysql_cluster.cnf
我们会发现这里没有最初的[server1]的配置了,这是由于MHA实现了故障切换,会从配置文件踢掉故障的节点,我们需要修改的是将[server1]加进去,并且指定[server1]作为下一次故障后的主节点
修改后的配置,需要注意的是加入[server1]后,额外添加candidate_master=1
指定下次故障后[server1]作为主节点,并注释掉[server2]里面的candidate_master=1
3、检查MHA的可用性、验证集群状态
- 检查MHA复制健康状态(确保所有节点正常)
masterha_check_repl --conf=/etc/mha/mysql_cluster.cnf
返回值为:MySQL Replication Health is OK.
- 检查 SSH 免密登录
masterha_check_ssh --conf=/etc/mha/mysql_cluster.cnf
返回值为:All SSH connection tests passed successfully.
- 重启MHA Manager服务(使配置生效)
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状态
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
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 从旧主库迁移到新主库。
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_FILEecho "[$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>&1return $?
}# -------------------------- 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 3ssh_exec "$host" "ifconfig $VIRTUAL_INTERFACE 2>/dev/null | grep -q '$VIP'"if [ $? -eq 0 ]; thenlog "$host VIP添加成功"return 0elselog "$host VIP添加失败"return 1fi
}# 移除VIP
vip_remove() {local host="$1"log "从 $host 移除VIP:$VIP(接口:$VIRTUAL_INTERFACE)"ssh_exec "$host" "ifconfig $VIRTUAL_INTERFACE down"sleep 2ssh_exec "$host" "ifconfig $VIRTUAL_INTERFACE 2>/dev/null | grep -q '$VIP'"if [ $? -ne 0 ]; thenlog "$host VIP移除成功"return 0elselog "$host VIP移除失败(可能已宕机)"return 0fi
}# 检查VIP状态(供status命令使用)
vip_check_status() {local host="$1"ssh_exec "$host" "ifconfig $VIRTUAL_INTERFACE 2>/dev/null | grep -q '$VIP'"if [ $? -eq 0 ]; thenlog "VIP在 $host 上存在"return 0elselog "VIP在 $host 上不存在"return 1fi
}# -------------------------- 参数解析与处理 --------------------------
# 解析键值对参数(状态检查时使用)# 解析键值对参数(状态检查时使用)# 解析键值对参数(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 "$@"; docase "$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#*=}" ;;esacdone# 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" instart)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 ]; thenhandle_position_params "$1" "$2" "$3" "$4" "$5" "$6"elselog "错误:位置参数数量不正确(实际$#个,需5或6个)"exit 1fi
filog "===== 脚本执行结束 ====="
exit 0
脚本使用说明
这个脚本完全符合需求:
1、仅在 MHA Manager 节点部署
2、使用你预先在主库手工配置的 VIP(通过ifconfig ens33:1 10.0.0.55/24)
3、实现 VIP 透明切换功能,应用无需感知数据库主从切换
配置步骤
首先在主库手工配置 VIP(这是你的要求):
#在MySQL主库服务器上执行
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
vim /usr/local/bin/master_ip_failover.sh
在 Manager 节点配置脚本:
复制上述脚本到 MHA Manager 节点(如/usr/local/bin/目录)
修改脚本顶部的配置区域,确保与你的环境一致:
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配置文件路径
赋予执行权限:
chmod +x /usr/local/bin/master_ip_failover.sh
要让 MHA 在检测到主库故障并完成切换后自动调用此脚本迁移 VIP,需要修改 MHA 配置文件:
[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 启动
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 停止
masterha_stop --conf=/etc/mha/mysql_cluster.cnf
- 3、检查 MHA 状态
masterha_check_status --conf=/etc/mha/mysql_cluster.cnf
- 4、检查 SSH 免密登录
masterha_check_ssh --conf=/etc/mha/mysql_cluster.cnf
- 5、检查主从复制
masterha_check_repl --conf=/etc/mha/mysql_cluster.cnf
这里就可以看到主从架构、以及VIP在哪台服务器
7、停掉主库mysql(模拟mysql故障)、在主库服务器执行
systemctl stop mysqld
- 1、删除报错文件(如果有)
rm -f /var/log/mha/mysql_cluster/mysql_cluster.failover.error
- 2、观测VIP脚本日志
tail -f /var/log/mha/vip_failover.log
可以看到VIP由原主库【10.0.0.61】变到新主库【10.0.0.60】上了
在【10.0.0.60】查看VIP信息,确实有了
- 3、查看MHA日志
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邮箱告警的配置。