VIP + Orchestrator + 自定义脚本 MySQL 高可用方案

📅 2026/7/12 2:03:36
VIP + Orchestrator + 自定义脚本 MySQL 高可用方案
目录1. 现状2. 目标3. 方案4. 流程5. 实现1主库高可用1. 配置 Orchestrator 钩子2. 准备环境3. 编写 VIP 漂移脚本2从库高可用1. 现状MySQL 实例主172.21.1.11:18251从1172.21.1.228:18251从2172.21.1.229:18251其中主和从1承载业务任何一个挂掉都必须手工处理才能恢复业务长时间中断。2. 目标主、从1任何一个挂掉业务秒级报错后自动恢复全程不用人工干预。3. 方案vip orchestrator 自定义脚本需要两个vipm_vip、s_vip初始 m_vip 在主库上s_vip 在从1上。主挂了m_vip 漂移到其中一个从上从1挂了s_vip 漂移到从2上。4. 流程主库挂掉1orchestrator 5秒发现2将其中最新一个从库提升为主库3将其他剩余从库指向新主库4钩子执行自定义脚本漂移 m_vip。5业务恢复全程自动只需要编写 m_vip 漂移脚本。从1挂掉1发现库挂了2漂移 s_vip3业务恢复全程自动但需要编写脚本检测 mysql 服务并触发 s_vip 漂移并自行调度执行。orchestrator 不会进行失败切换也没有相应的钩子。5. 实现1主库高可用Orchestrator 3.2.6 通过 PostMasterFailoverProcesses 调用钩子脚本实现 VIP 漂移核心思路是在配置文件里定义好钩子脚本和传递给它的参数然后这个脚本会通过 SSH 远程操作新旧主库在新主库上添加 VIP并从旧主库上移除 VIP。整个配置流程可以分为三个主要步骤。orchestrator 配置了三台的 raft 集群因此以下配置需要在三台上都执行。1. 配置 Orchestrator 钩子在 Orchestrator 的配置文件/home/mysql/orchestrator/orchestrator.conf.json中设置 PostMasterFailoverProcesses 参数。这个参数定义了一个命令列表它们会在主库故障转移流程成功完成后被执行。{ // ... 其他配置 ... PostMasterFailoverProcesses: [ /home/mysql/orchestrator/vip_failover.sh {failureType} {failureClusterAlias} {failedHost} {successorHost} ] // ... 其他配置 ... }Orchestrator 会用实际的值替换掉花括号里的变量然后作为位置参数传递给脚本。修改配置文件后重启 orchestrator 服务以生效。三台依次执行systemctl daemon-reload systemctl reset-failed orchestrator systemctl stop orchestrator systemctl start orchestrator sleep 10 systemctl status orchestratorOrchestrator Raft 集群部署参见https://blog.csdn.net/wzy0623/article/details/162634623#t112. 准备环境在钩子脚本能正常工作之前必须完成两项关键的基础环境配置。1建立 SSH 互信Orchestrator 服务器需要能够使用 mysql 用户免密码 SSH 登录到集群中的每一台 MySQL 服务器包括旧主和新主。这是脚本能够远程执行 VIP 管理命令的前提。# 在三台机器用 mysql 用户依次执行 ssh-keygen ssh-copy-id 172.21.1.11 ssh-copy-id 172.21.1.228 ssh-copy-id 172.21.1.2292把 mysql 用户的公钥放到每个机器的 root# 在三台机器用 mysql 用户依次执行 ssh-copy-id -i ~/.ssh/id_rsa.pub root172.21.1.11 ssh-copy-id -i ~/.ssh/id_rsa.pub root172.21.1.228 ssh-copy-id -i ~/.ssh/id_rsa.pub root172.21.1.2293. 编写 VIP 漂移脚本以下是一个可用的脚本它根据 Orchestrator 传递的参数执行 VIP 的删除和添加操作。脚本/home/mysql/orchestrator/vip_failover.sh#!/bin/bash # # 脚本名称: vip_failover.sh # 适用场景: GitHub Orchestrator 主从切换Failover时的高可用 VIP 漂移脚本 # # --- 参数接收 (由 Orchestrator 自动传入) --- FAILURE_TYPE$1 CLUSTER_ALIAS$2 OLD_MASTER_IP${3%%:*} # 自动剥离可能存在的端口号 (如 192.168.1.10:3306 - 192.168.1.10) NEW_MASTER_IP${4%%:*} # --- 基础配置 (请根据实际环境修改) --- VIP172.21.1.9 NETMASK24 INTERFACEeth0 LOG_FILE/home/mysql/orchestrator/vip_failover.log # --- 权限与参数校验 --- if [[ -z $FAILURE_TYPE || -z $NEW_MASTER_IP ]]; then echo $(date %Y-%m-%d %H:%M:%S) [WARN] FAILURE_TYPE or NEW_MASTER_IP is empty. Skip VIP action. $LOG_FILE exit 0 fi # 日志函数 log() { local level$1 local msg$2 echo $(date %Y-%m-%d %H:%M:%S) [$level] $msg $LOG_FILE } # 核心广播 ARP 刷新网络拓扑 arp_refresh() { local host$1 log INFO Sending gratuitous ARP from $host... # 使用 arping 向局域网广播最新的 MAC-IP 映射关系 (发送3次间隔0.5秒) ssh -o ConnectTimeout3 -o StrictHostKeyCheckingno root$host \ arping -U -c 3 -I $INTERFACE $VIP $LOG_FILE 21 } # --- 主逻辑开始 --- # 仅针对主库级别的故障进行 VIP 漂移 if [[ $FAILURE_TYPE ~ ^(DeadMaster|MasterFailover|ForceMasterFailover)$ ]]; then log INFO Starting VIP Failover log INFO Reason: $FAILURE_TYPE | Cluster: $CLUSTER_ALIAS log INFO Path: $OLD_MASTER_IP $NEW_MASTER_IP # 1. 尝试从旧主库卸载 VIP if [[ -n $OLD_MASTER_IP ]]; then log INFO Step 1: Removing VIP from Old Master ($OLD_MASTER_IP)... # 设置更短的超时时间(3秒)。即使旧主死机卡住也不影响新主接管。 ssh -o ConnectTimeout3 -o StrictHostKeyCheckingno root$OLD_MASTER_IP \ ip addr del $VIP/$NETMASK dev $INTERFACE $LOG_FILE 21 if [ $? -eq 0 ]; then log INFO Successfully removed VIP from Old Master. else log WARN Failed to remove VIP from Old Master (This is normal if the host is dead). fi fi # 2. 在新主库上绑定 VIP log INFO Step 2: Binding VIP to New Master ($NEW_MASTER_IP)... # 先尝试清理新主库上可能残留的相同 VIP防止 IP 冲突报错 ssh -o ConnectTimeout5 -o StrictHostKeyCheckingno root$NEW_MASTER_IP \ ip addr del $VIP/$NETMASK dev $INTERFACE 2/dev/null; ip addr add $VIP/$NETMASK dev $INTERFACE $LOG_FILE 21 if [ $? -eq 0 ]; then log INFO Successfully bound VIP to New Master. # 3. 刷新 ARP 缓存最关键的一步 arp_refresh $NEW_MASTER_IP else log FATAL CRITICAL: Failed to bind VIP to New Master! exit 1 fi log INFO VIP Failover Finished else log INFO Ignore failure type $FAILURE_TYPE. No VIP action required. fi将此脚本保存后别忘了赋予它执行权限 chmod x /home/mysql/orchestrator/vip_failover.sh。2从库高可用orchestrator 帮不上忙只能自己编写脚本检测 mysql 服务并触发 s_vip 漂移并自行调度执行。/home/mysql/orchestrator/slave_vip_monitor.sh 内容如下#!/bin/bash source /home/mysql/.bash_profile VIP172.21.1.8 NETMASK24 INTERFACEeth0 OTHER_IP172.21.1.229 # 在229上改成 172.21.1.228 LOG_FILE/home/mysql/orchestrator/slave_vip_monitor.log MYSQL_SOCKET/data/18251/mysqldata/mysql.sock MYSQL_USERroot MYSQL_PASSWORD123456 log() { echo $(date %Y-%m-%d %H:%M:%S) [$1] $2 $LOG_FILE; } check_mysql() { mysqladmin -u $MYSQL_USER -p$MYSQL_PASSWORD -S $MYSQL_SOCKET ping 2/dev/null | grep -q mysqld is alive; } check_vip_local() { ssh -o ConnectTimeout3 -o StrictHostKeyCheckingno root127.0.0.1 \ ip addr show $INTERFACE 2/dev/null | grep -q $VIP/$NETMASK 2/dev/null; } log INFO Started, VIP: $VIP # VIP不在本机直接退出 if ! check_vip_local; then log INFO VIP not local, exit exit 0 fi # 循环3次检查MySQL每次间隔5秒 FAIL_COUNT0 for i in 1 2 3; do if check_mysql; then log INFO MySQL alive exit 0 else ((FAIL_COUNT)) log WARN MySQL dead ($FAIL_COUNT/3) fi if [ $i -lt 3 ]; then sleep 5 fi done log WARN Failover to $OTHER_IP # 和vip_failover.sh一样通过SSH执行删除 ssh -o ConnectTimeout3 -o StrictHostKeyCheckingno root127.0.0.1 \ ip addr del $VIP/$NETMASK dev $INTERFACE $LOG_FILE 21 # 远程添加 ssh -o ConnectTimeout5 -o StrictHostKeyCheckingno root$OTHER_IP \ ip addr del $VIP/$NETMASK dev $INTERFACE 2/dev/null; ip addr add $VIP/$NETMASK dev $INTERFACE $LOG_FILE 21 ssh -o ConnectTimeout3 -o StrictHostKeyCheckingno root$OTHER_IP \ arping -U -c 3 -I $INTERFACE $VIP $LOG_FILE 21 log INFO Failover done, exit exit 0调度执行* * * * * /home/mysql/orchestrator/slave_vip_monitor.sh * * * * * sleep 20 /home/mysql/orchestrator/slave_vip_monitor.sh * * * * * sleep 40 /home/mysql/orchestrator/slave_vip_monitor.sh两台从库机器都要部署。正常检测周期Cron触发频率每20秒一次0秒、20秒、40秒各执行一次每次执行的最大耗时约15秒3次检查 × 5秒间隔切换触发条件当MySQL故障时需要满足VIP在本机立即满足连续3次检查MySQL失败每次间隔5秒执行切换操作SSH命令约1-3秒时间范围估算最快切换时间场景cron刚好在执行第一次检查就发现MySQL故障时间0 5 5 2 ≈ 12秒最慢切换时间场景MySQL刚故障时cron刚执行完需要等下一个周期时间20秒等待cron 15秒3次检查 2秒切换 ≈ 37秒具体时间轴示例假设MySQL在 10:00:00 故障10:00:00 - MySQL故障 10:00:00 - cron刚执行完最坏情况 10:00:20 - cron执行第1次检查 → 失败 10:00:25 - 第2次检查 → 失败 10:00:30 - 第3次检查 → 失败 10:00:32 - 切换完成总耗时32秒