MySQL MHA-Go 部署说明
本文说明 mha_go.yml 的支持边界与基础使用方式。mha_go.yml 部署的是 Go 重写的 MHA 管理器(mha-go),它不再依赖 Perl MHA 工具链,以单个静态二进制 + 一份 YAML 配置的形式运行在 manager 节点上。
1. 原理
mha-go 采用"控制器主循环 + 从库侧观察者"的架构,围绕 GTID 复制做故障检测与切换:
- 主循环:manager 进程以
controller.monitor.interval(默认 2s)为周期探测所有节点。连续failure_threshold(默认 3 次)判定异常后,再经过reconfirm_timeout(默认 5s)二次确认,才进入 failover 流程,避免抖动误判。 - Secondary observer:除了 manager 自己探测,
cluster.yaml会为每个 replica 注册一个secondary_checks条目,由 replica 节点反向确认主库存活,防止 manager 单点网络分区导致误切。 - Lease 选主:
controller.lease.backend: local-memory,TTL 15s,确保同一时刻只有一个 manager 实例做出切换决策。 - GTID-only 恢复:复制模式固定为
gtid,不再依赖 relay log diff / binlog 位置拼接。replication.salvage.policy: salvage-if-possible决定是否在主库失联时尽力追补丢失事务。 - 半同步偏好:
semi_sync.policy: preferred+wait_for_replica_count,在可用时优先走半同步确认,在超时后平滑降级。 - 候选优先级:
slave_ips的顺序直接映射到candidate_priority(100、90、80……),用于 failover 时选定新主。 - 写入端点抽象:
writer_endpoint是独立一层,默认none,开启vip模式后由 manager 调/usr/local/bin/mha_ip_failover.sh完成 VIP 漂移;未来可替换为 proxy / DNS 等其他实现,不影响控制面。 - 执行形态:manager 以
mysql用户通过systemd常驻,日志走 JSON 格式输出到 journal。所有 CLI 动作收敛到一个mha二进制的子命令。
2. 与传统 MHA 的对比
mha.yml 部署的是社区 Perl 版 MHA,mha_go.yml 部署的是 Go 重写版本。二者定位都是"一主多从 + 独立 manager 做故障切换",但在实现与使用边界上差异明显:
| 维度 | 传统 MHA (mha.yml) | MHA-Go (mha_go.yml) |
|---|---|---|
| 实现语言 | Perl | Go,单个静态二进制 |
| OS 支持 | 仅 CentOS 7.5 / EL7 | CentOS 7/8、RHEL 7/8、Rocky 9、BigCloud 7/8/21、openEuler 20/22/24、Anolis OS 8、Kylin V10 |
| MySQL 支持 | 5.7 | 8.0 / 8.4 |
| 外部依赖 | Perl + MHA RPM + DBD::mysql 等 | 无额外 RPM,单二进制下发 |
| 运行形态 | masterha_manager 前台 / nohup 后台 | systemd 常驻服务(mha-manager.service) |
| 运行用户 | 通常 root | mysql 用户,最小权限 |
| 配置格式 | INI (app1.cnf) | YAML (cluster.yaml) |
| 日志 | 文本日志 | JSON 结构化日志,直接进 journal |
| 复制模式 | binlog 位置 / GTID 均可 | 仅 GTID |
| 故障检测 | manager 单点 ping | manager 主循环 + replica 侧 secondary_checks 二次确认 |
| 失败阈值 | ping_interval × 次数 | failure_threshold 与 reconfirm_timeout 解耦 |
| 丢失事务抢救 | SSH 到死主 copy binlog,拼 relay log | GTID 原生恢复,salvage.policy 策略化 |
| 选主优先级 | candidate_master / no_master 标签 | candidate_priority 0–100,按 slave_ips 顺序递减 |
| 写入端点 | VIP 漂移脚本硬编码 | writer_endpoint 抽象层(none / vip,可扩展) |
| CLI | 多个 masterha_* 命令 | 统一 mha <subcommand>(check-repl / manager / switch / failover-plan / failover-execute / version) |
| Dry-run | 无 | --dry-run 一等支持 |
| 发布方式 | 分发 RPM,独立版本 | 随 dbbot 发版,与剧本同节奏 |
简单判断:新建集群优先 mha_go.yml;仅当你仍需要维护 MySQL 5.7 + CentOS 7.5 的历史拓扑时,才继续使用 mha.yml。
3. 支持边界
- 目标架构:一主多从 + 一个独立 MHA-Go Manager
- 复制模式:必须为
GTID复制,推荐semi_sync半同步 - 适用版本:MySQL
8.0/8.4 - OS 支持范围与
mysql_ansible其他剧本一致,当前包含CentOS 7/8、RHEL 7/8、Rocky 9、BigCloud 7/8/21、openEuler 20/22/24、Anolis OS 8、Kylin V10
4. 拓扑约定
mha_go.yml 复用 [dbbot_mysql] 主机组,通过 master_ip / slave_ips / manager_ip 三个变量区分节点角色:
master_ip:主库,接收写入;在cluster.yaml中登记为db1,角色为primary。slave_ips:从库列表,至少一台;在cluster.yaml中登记为db2、db3……角色为replica。manager_ip:运行mha-manager进程的节点,必须在slave_ips之内,不能与master_ip相同。默认取slave_ips的最后一台。
cluster.yaml 中从库的 candidate_priority 按 slave_ips 顺序递减:第一个从库 100、第二个 90,依此类推,用于主库故障后选主。
5. inventory 示例
[dbbot_mysql]
192.168.199.131 ansible_user=root ansible_ssh_pass="'<your_ssh_password>'"
192.168.199.132 ansible_user=root ansible_ssh_pass="'<your_ssh_password>'"
192.168.199.133 ansible_user=root ansible_ssh_pass="'<your_ssh_password>'"
[all:vars]
ansible_python_interpreter=auto_silent
6. 关键变量
编辑 mysql_ansible/playbooks/vars/var_mha_go.yml:
master_ip: 192.168.199.131
slave_ips:
- 192.168.199.132
- 192.168.199.133
# manager 默认放在 slave_ips 的最后一台,如需调整请显式填写
manager_ip: "{{ slave_ips[-1] }}"
# cluster.yaml 中的集群名,同时体现在 mha 日志和 systemd Unit 描述
mha_go_cluster_name: app1
# --- 写入端点(VIP 漂移脚本,可选) ---
# mha_go_writer_endpoint_enabled: true
# vip: 192.168.199.130
# vip_netmask: "32"
# net_work_interface: "ens33"
其他可覆盖的角色变量(一般保持默认):
| 变量 | 默认值 | 说明 |
|---|---|---|
mha_go_binary_dest | /usr/local/bin/mha | manager 节点上 mha 二进制落地位置 |
mha_go_config_dir | /etc/mha | cluster.yaml 所在目录 |
mha_go_log_dir | /var/log/mha | manager 日志目录 |
mha_go_service_enabled | true | 是否 systemctl enable manager 服务 |
mha_go_writer_endpoint_enabled | false | 是否启用 VIP 漂移(开启后需填 vip / vip_netmask / net_work_interface) |
7. 前置条件
make_mha_go 在执行前会做以下检查,任何一项不满足都会直接失败:
- 每个节点的
datadir下必须存在master_slave_finish.flag,即 MySQL 已由 dbbot 安装并完成主从搭建。 - manager 节点
/tmp/ssh_finish.flag必须存在,即make_ssh_passwordless已跑过。 - 所有节点
SELECT @@gtid_mode必须为ON。
mha_go.yml 本身的 role 执行顺序已经按这个依赖编排:
pre_check_and_set → mysql_server → make_replication → make_ssh_passwordless → make_mha_go
也就是说你只需要直接跑 mha_go.yml,不需要提前手工跑其他剧本。
8. 执行入口
cd /usr/local/dbbot/mysql_ansible/playbooks
ansible-playbook mha_go.yml
非交互式执行(例如在 CI 或自动化流水线中)可以跳过 confirmation.yml 的 pause 提示:
ansible-playbook mha_go.yml -e dbbot_confirmation_input=confirm
9. 执行后产物
剧本执行成功后,manager 节点上会出现:
/usr/local/bin/mha:Go 版 MHA 静态二进制,mha version返回mha-go 0.x.y。/etc/mha/cluster.yaml:集群定义,角色db1=primary、db2..=replica,复制模式gtid,半同步策略preferred。/etc/systemd/system/mha-manager.service:Type=simple 的 systemd 单元,以{{ mysql_user }}身份启动mha manager --config /etc/mha/cluster.yaml --log-format json。/var/log/mha/:日志目录(JSON 格式输出,systemd 通常同时走 journal)。
所有节点(主、从、manager)的 datadir 都会多出 mha_go_finish.flag,供后续剧本识别。
10. 常用命令
全部运行在 manager 节点,mha 二进制即 /usr/local/bin/mha:
# 查看版本
mha version
# 只做一次性配置与复制健康检查,不启动 manager
mha check-repl --config /etc/mha/cluster.yaml
# 打印故障转移计划(dry run,不执行)
mha failover-plan --config /etc/mha/cluster.yaml
# 指定候选节点执行 failover
mha failover-execute --config /etc/mha/cluster.yaml --candidate db2
# 主动切换到指定新主(受控切换)
mha switch --config /etc/mha/cluster.yaml --new-primary db2 --dry-run
服务状态与日志:
systemctl status mha-manager
journalctl -u mha-manager -f
11. 启用 VIP 写入端点
默认部署不启用 VIP,cluster.yaml 的 writer_endpoint.kind 为 none。如果需要对外暴露固定写入 VIP:
在
vars/var_mha_go.yml中打开:mha_go_writer_endpoint_enabled: true vip: 192.168.199.130 vip_netmask: "32" net_work_interface: ens33剧本会额外执行
edit_sudoer.yml和deploy_vip_script.yml,在所有 MySQL 节点为mysql用户添加ip addr/arping相关的 sudo 规则,并在 manager 节点落下/usr/local/bin/mha_ip_failover.sh。cluster.yaml中的writer_endpoint会切换为:writer_endpoint: kind: vip target: <vip> command: /usr/local/bin/mha_ip_failover.shvip/vip_netmask/net_work_interface必须与实际网络一致,vip必须是一个合法 IP,vip_netmask取值范围0–32。
12. 注意事项
manager_ip必须是slave_ips中的一员;validate_mha_go.yml会在 inventory / vars 不一致、manager 指向主库时主动 fail。slave_ips中每个 IP 都必须同时在inventory/hosts.ini里出现,反过来也一样,不允许"inventory 有但 vars 没有"。mha-manager.service以mysql用户身份运行,cluster.yaml权限0640,属主必须是mysql:mysql。- 失败后重跑前,建议先确认:manager 节点
mha-manager服务状态、cluster.yaml是否被手工改过、各节点 GTID 与复制状态是否一致。 - 离线环境需要先把 yum 依赖(
python3-libselinux、ncurses-compat-libs、numactl、libaio、tar)准备好,否则pre_check_and_set阶段会在 yum 刷元数据时失败。