
不少运维同学在接手内网数据库环境时都会面对一个很现实的问题应用要求 MySQL 高可用机器却在完全隔离的机房没有外网、没有现成的 yum 源连装个软件都要靠 U 盘拷包。这种情况下想引入 Orchestrator 来管理主从复制、做自动故障切换难点不在工具本身而在离线依赖的收集和配置细节。这篇文章就围绕 CentOS 7 离线安装 Orchestrator 并实现 MySQL 高可用的完整步骤把从依赖准备、服务初始化、实例纳管到故障自动切换的整个流程走一遍。内容面向需要在隔离网络内快速搭建 MySQL 高可用管理面的运维、DBA以及正在做数据库平台的同学全程基于可复现的内网做法少绕弯子直接抄作业。1. 整体方案为什么选 Orchestrator怎么搭最省心1.1 相比传统方案的优势先说说为什么选 Orchestrator 而不是其他方案。早些年很多团队用的是 MHA那套架构本身没大问题但 Manager 节点要做额外的脚本管理和 SSH 免密拓扑发现基本靠手工维护切换脚本多年没更新。Orchestrator 是另一个思路它本身是一个 Go 写的 Web 服务加命令行工具能自动发现 MySQL 主从复制拓扑维护复制关系支持一键手动切换、故障自动恢复还带了 HTTP API可以跟公司内部的运维平台对接。最方便的一点是它把整个拓扑可视化了出来主从关系、复制延迟、实例状态在页面上看得清清楚楚。Orchestrator 对 MySQL 版本和复制方式的兼容也让人省心。不管是 MySQL 5.7 还是 8.0GTID 复制还是传统位点复制都能纳管。对 CentOS 7 这种老系统来说安装依赖也少核心就是一个 RPM 包离线部署的难度比想象中低很多。1.2 拓扑架构规划高可用方案要落地先要把机器角色规划好。我这里用一个比较典型的场景做示例三台服务器一台主库两台从库Orchestrator 服务端和其中一台从库放在同一台机器上后端元数据库也放在这台机器的 MySQL 实例里。角色IP实例端口说明主库 master-1192.168.1.713306提供读写故障时会被自动摘除从库 replica-1192.168.1.723306普通从库作为候选新主从库 replica-2 orchestrator192.168.1.733306 / 3000部署 Orchestrator 服务后端库也落在本机生产环境里如果条件允许我建议把 Orchestrator 独立到一台小机器上或者直接做三节点 raft 集群防止控制面本身变成单点。后面我会单独说这个事但第一步先用这个最简单的架构把流程跑通。1.3 离线包收集思路离线环境最头疼的其实是依赖收集。Orchestrator 的 RPM 包依赖很少安装时基本不会报错但整个高可用链路里还有个隐形成员MySQL 客户端。Orchestrator 在部分流程里会调用 mysql 命令来测试连接或执行脚本所以目标机器上最好有一份能用的 mysql 客户端CentOS 7 自带的 mariadb 客户端也可以。我的建议是这样的第一步在一台有外网且系统版本一致同为 CentOS 7的临时机器上用 yumdownloader 把需要的系统依赖包全部拉下来# 先装 yum-utils yum install -y yum-utils mkdir -p /opt/offline-rpms cd /opt/offline-rpms # 如果目标机器需要全新安装 MySQL把 MySQL 相关 RPM 也拉下来 yumdownloader --resolve --destdir. mysql-community-server mysql-community-client mysql-community-libs mysql-community-common # 如果目标机器已有 MySQL只需要 mysql 客户端 yumdownloader --resolve --destdir. mysql-community-client mysql-community-libs mysql-community-common第二步从 Orchestrator 官方 Release 页面下载 orchestrator 和 orchestrator-cli 两个 RPM放到同一个目录。版本建议用 3.2.x比如 3.2.6功能稳定网上能查到的资料也多。第三步把整个目录拷贝到离线服务器上。如果离线服务器有内网 yum 源直接 rpm -ivh 逐个安装也可以如果机器比较干净我建议顺手做一个本地 yum 源后续装其他依赖会方便很多# 在离线服务器上执行 mkdir -p /opt/offline-rpms # 把拷贝过来的 rpm 放到这个目录 cd /opt/offline-rpms createrepo . # 如果没有 createrepo先装一下 cat /etc/yum.repos.d/local-offline.repo EOF [local-offline] nameLocal Offline RPMs baseurlfile:///opt/offline-rpms enabled1 gpgcheck0 EOF yum clean all yum makecache有了这个本地源后面安装任何依赖都简单了。这一步值得多花几分钟比后面缺一个依赖抓瞎强得多。2. 正式安装 Orchestrator 与核心配置2.1 安装步骤与目录结构离线包准备好之后安装本身非常快。在目标机器上执行cd /opt/offline-rpms rpm -ivh orchestrator-*.rpm orchestrator-cli-*.rpm装完之后关注这几个关键位置/usr/bin/orchestrator服务端主程序运行后监听 HTTP 端口。/usr/bin/orchestrator-cli命令行客户端日常维护和手动切换靠它。/etc/orchestrator.conf.json主配置文件。/var/lib/orchestrator数据目录默认放 SQLite 数据库和其他临时文件。/var/log/orchestrator.log日志文件位置配置里可以修改。RPM 装完会同时生成 systemd 服务文件直接用 systemctl 管理。默认情况下服务不会自动启动需要我们先完成配置。2.2 配置文件逐项拆解这是整个搭建过程最核心的部分。直接给一份我在实际项目中验证过的配置照着改 IP 和密码就能用。后端数据库我建议用 MySQL不要用默认的 SQLite原因后面说。{ Debug: false, ListenAddress: :3000, MySQLTopologyUser: orc_user, MySQLTopologyPassword: orc_pass_2024, BackendDB: mysql, MySQLOrchestratorHost: 192.168.1.73, MySQLOrchestratorPort: 3306, MySQLOrchestratorDatabase: orchestrator, MySQLOrchestratorUser: orc_meta, MySQLOrchestratorPassword: orc_meta_pass_2024, InstancePollSeconds: 5, AutoFailover: true, RecoveryPeriodBlockSeconds: 30, FailureDetectionPeriodSeconds: 5, ReasonableMaintenanceReplicationLagSeconds: 20, DataCenterPattern: , PhysicalEnvironmentPattern: , DetectClusterAliasQuery: SELECT SUBSTRING_INDEX(hostname, ., 1), DiscoverByShowSlaveHosts: true, PromotionRule: prefer, LogLevel: INFO, LogFile: /var/log/orchestrator.log }几个关键参数我挑出来说一下MySQLTopologyUser和MySQLTopologyPassword这是 Orchestrator 用来连接被管 MySQL 实例的账号用于发现拓扑、获取状态、执行切换。权限是全局性的后面章节会给出授权语句。BackendDBOrchestrator 自己元数据存在哪。默认支持 mysql 和 sqlite。单机测试用 SQLite 最省事但生产环境我强烈建议用 MySQL。因为后端 MySQL 和 Orchestrator 可以做成 raft 集群模式元数据也能被监控系统读取排查问题方便得多。而且 Orchestrator 在切换过程中要记录大量事件和数据SQLite 在高并发写入时锁竞争明显。InstancePollSecondsOrchestrator 每隔多少秒轮询一次 MySQL 实例状态。默认 5 秒够用。这个值别调太小比如改成 1 秒一旦网络抖动容易误判实例故障触发不必要的切换。AutoFailover这是总开关。不开的话 Orchestrator 只做发现和展示不会自动切换。新手第一次搭建建议先不开手动切换跑通之后再打开避免配置失误导致生产事故。RecoveryPeriodBlockSeconds一次自动切换完成之后多少秒内不再触发新的恢复动作。防止恢复过程中反复横跳30 秒是我常用值。DetectClusterAliasQuery用来给集群起别名。通过这个 SQL 从实例取一个字段作为集群名字方便在 Web 页面上区分不同集群。集群别名在切换和应用侧联动时很有用。PromotionRule候选从库的默认优先规则。prefer 表示优先提升配合后面给实例打标签能控制故障时选谁当新主。2.3 初始化后端数据库并启动服务后端选了 MySQL就要先把 orchestrator 元数据库准备好。登录 192.168.1.73 的 MySQL执行CREATE DATABASE IF NOT EXISTS orchestrator DEFAULT CHARACTER SET utf8mb4; CREATE USER orc_meta192.168.1.% IDENTIFIED BY orc_meta_pass_2024; GRANT ALL PRIVILEGES ON orchestrator.* TO orc_meta192.168.1.%; FLUSH PRIVILEGES;注意这里账号的 host 范围建议写成具体网段别直接给%安全一点。数据库和账号准备好之后启动服务。Orchestrator 第一次启动时会自动在 orchestrator 库中创建所有数据表不需要手工导入 schemasystemctl enable orchestrator systemctl start orchestrator systemctl status orchestrator启动后验证一下# 看端口是否监听 ss -lntp | grep 3000 # 看日志有没有报错 tail -f /var/log/orchestrator.log如果一切正常打开浏览器访问http://192.168.1.73:3000就能看到 Orchestrator 的 Web 页面。页面上一开始是空的因为还没有纳管任何 MySQL 实例。注意Orchestrator 默认 Web 页面是没有登录认证的内网环境还好如果网段里有其他部门的人建议在前端加一层反向代理做 Basic Auth或者用防火墙限制 3000 端口的访问来源。3. MySQL 主从复制环境与纳管3.1 主从复制基础配置Orchestrator 管理的是活生生的 MySQL 复制环境不是空转的玩具。所以先把三台机器的 MySQL 主从复制搭起来。我用 GTID 模式这台切换逻辑最简单Orchestrator 对 GTID 的支持也最完善。三台机器的 MySQL 配置文件/etc/my.cnf里服务端参数这样设置。主库 192.168.1.71[mysqld] server_id71 log_binmysql-bin gtid_modeON enforce_gtid_consistencyON binlog_formatROW log_slave_updatesON skip_name_resolve0从库 192.168.1.72[mysqld] server_id72 log_binmysql-bin gtid_modeON enforce_gtid_consistencyON binlog_formatROW log_slave_updatesON skip_name_resolve0 read_onlyON从库 192.168.1.73[mysqld] server_id73 log_binmysql-bin gtid_modeON enforce_gtid_consistencyON binlog_formatROW log_slave_updatesON skip_name_resolve0 read_onlyON这里有个经常被忽略的点log_slave_updates一定要开。它决定了从库是否把从主库同步过来的变更继续记录到自己的 binlog。如果不开一旦这个从库被提升为新主它的下游从库会瞬间断掉整个复制链就断了。Orchestrator 做级联拓扑调整时也依赖这个参数。配置好后重启三台 MySQL。然后在主库上创建复制账号CREATE USER repl_user192.168.1.% IDENTIFIED BY repl_pass_2024; GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO repl_user192.168.1.%; FLUSH PRIVILEGES;两个从库上执行 CHANGE MASTER-- 192.168.1.72 上执行 CHANGE MASTER TO MASTER_HOST192.168.1.71, MASTER_PORT3306, MASTER_USERrepl_user, MASTER_PASSWORDrepl_pass_2024, MASTER_AUTO_POSITION1; START SLAVE; -- 192.168.1.73 上执行 CHANGE MASTER TO MASTER_HOST192.168.1.71, MASTER_PORT3306, MASTER_USERrepl_user, MASTER_PASSWORDrepl_pass_2024, MASTER_AUTO_POSITION1; START SLAVE;验证一下主从状态SHOW SLAVE STATUS\G看到Slave_IO_Running: Yes和Slave_SQL_Running: Yes说明复制正常。有任何一个不是 Yes先排查网络和账号权限别急着往下走。3.2 给 Orchestrator 创建监控账号复制搭好之后要给 Orchestrator 创建连接拓扑实例的账号。这个账号会被 Orchestrator 用来读取实例状态、获取 binlog 位置、发起切换。官方推荐的最小权限如下-- 在三台 MySQL 实例上都执行 CREATE USER orc_user192.168.1.% IDENTIFIED BY orc_pass_2024; GRANT SELECT, SUPER, RELOAD, PROCESS, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO orc_user192.168.1.%; FLUSH PRIVILEGES;解释一下每个权限的用途SELECT读取实例基础状态。SUPER切换时修改 read_only、执行 CHANGE MASTER 等管理操作。RELOAD刷新权限等。PROCESS读取线程状态和复制状态。REPLICATION SLAVE、REPLICATION CLIENT读取复制信息执行复制控制。有人会图省事直接GRANT ALL,我不推荐。最小权限原则在数据库高可用这种敏感场景下尤其重要万一账号泄露起码不会让攻击者拿到全部权限。3.3 实例纳管和候选从库设置现在可以开始让 Orchestrator 干活了。用命令行把三台实例加进去# 在 192.168.1.73 上执行 orchestrator-cli -c discover -i 192.168.1.71:3306 orchestrator-cli -c discover -i 192.168.1.72:3306 orchestrator-cli -c discover -i 192.168.1.73:3306执行完再刷新一下 Web 页面应该能看到一个完整的主从拓扑图主库 71 在顶端72 和 73 挂在下面。如果只有部分实例出现或者状态列显示异常先回第 2 节检查配置账号八成是连不上。接下来设置候选从库。默认 Orchestrator 会按 PromotionRule 参数决定优先提升谁但保险起见要把最重要、配置最好的从库明确标记为候选。比如让 192.168.1.72 优先成为新主orchestrator-cli -c register-candidate -i 192.168.1.72:3306 -f prefer这个命令的意思是给实例打上“优先候选”标签。以后主库挂了Orchestrator 会优先选择这台机器做新主。如果担心另一台机器配置较差还可以打上must_not标签防止它被提升。must_not一般用在灾备节点或者测试从库上。到这一步基础纳管已经完成。Web 页面能看拓扑命令行能查状态。先别急着开自动切换一定要先把手动切换流程走一遍。4. 手动切换演练与自动故障切换实测4.1 手动切换走一遍流程手动切换是验证配置是否正确的最快方式。立刻上自动切换一旦参数有问题可能直接把生产搞挂。手动切换用 Orchestrator 的graceful-master-takeover命令orchestrator-cli -c graceful-master-takeover -i 192.168.1.72:3306这条命令的意思是把 192.168.1.72 提升为新主库并让原来的主库 71 变成新主的从库。执行过程中 Orchestrator 会检查候选从库的复制延迟、数据一致性、账号权限如果不过会直接拒绝执行。切换完成后再看 Web 页面拓扑应该变成了72 在最顶端71 和 73 都挂在 72 下面。同时确认orchestrator-cli -c topology -i 192.168.1.72:3306输出里应该能看出 71 变成了 72 的从库复制状态正常。到这里手动切换链路已经通了自动切换的基础也就打好了。4.2 自动故障切换实测手动切换没问题后把配置里的AutoFailover: true打开重启 Orchestratorsystemctl restart orchestrator然后模拟主库宕机。最直接的方式是把主库的 mysqld 进程杀掉模拟断电宕机# 在 192.168.1.71 上执行 kill -9 $(cat /var/run/mysqld/mysqld.pid)等大约 30 到 60 秒打开 Web 页面观察发生了什么。正常情况下Orchestrator 会经历这几个阶段检测到主库 71 心跳丢失把实例状态标记为异常。进入故障检测流程再次确认 71 确实不可达。从存活的从库中根据 PromotionRule 选择新主这里应该是 72。对 72 执行 stop slave、reset slave all、set global read_only0把它提升为新主。把 73 重新指向新主 72执行 CHANGE MASTER TO MASTER_AUTO_POSITION1恢复复制。在 Web 页面里把 71 标记为失效从活动拓扑中摘除。整个过程我实测下来一般在半分钟内完成具体看InstancePollSeconds和网络延迟。如果切换后页面显示 72 为新主且 73 处于正常复制状态那恭喜自动故障切换已经真正生效了。4.3 原主恢复后如何重新加入自动切换只是高可用的前半场原主恢复后怎么加回来很多人容易忽略。这里有一个重要认知Orchestrator 默认不会把旧主自动重新挂回拓扑它会让旧主保持“待处理”状态需要人工确认。把原来的主库 71 重新启动之后我的处理流程是这样的# 在 71 上执行先确保它不会意外成为写入节点 mysql -e SET GLOBAL read_onlyON; SET GLOBAL super_read_onlyON;然后让它与新主 72 建立复制关系。这里千万不要手工去执行 CHANGE MASTER直接让 Orchestrator 来调整拓扑更稳# 先把 71 纳管进来 orchestrator-cli -c discover -i 192.168.1.71:3306 # 把它移动到 72 下面作为 72 的从库 orchestrator-cli -c move-below -i 192.168.1.71:3306 -d 192.168.1.72:3306Orchestrator 会自动把 71 的复制源设置成 72并且通过 GTID 自动完成数据追平。如果 71 的数据落后太多复制可能需要一段时间才能追上这段时间里监控一下复制延迟即可。等 71 完全追平新主 72就可以考虑把 read_only 关掉让它重新承担读写。这段流程最好做成操作手册需要人工执行。别指望全自动生产环境的故障恢复一定要保留人工确认环节。5. 常见问题与排查速查这套环境搭下来我把实际踩过的坑整理成一张速查表按出现频率排个序。现象原因解决办法Orchestrator 服务启动后端口没监听后端库连不上配置账号密码错误看日志 /var/log/orchestrator.log检查 BackendDB 配置确认 orc_meta 账号能远程登录Web 页面能看到实例但状态一直是 unknownMySQLTopologyUser 权限不足或网络不通在 73 上用 orc_user 手动 mysql -h 192.168.1.71 -P3306 试连确认权限实例可以 discover但页面显示复制关系错乱主机名解析不一致MySQL 里 report_host 写错在 /etc/hosts 中把所有节点 IP 和主机名写全保证同一条复制链中实例主机名唯一手动切换提示某个从库不可提升从库 read_onlyON 未关闭或 log_slave_updates 未开启检查参数从库必须开启 log_slave_updates且 Orch 需要能修改 read_only自动切换一直不触发AutoFailover 没开或集群被打了 downtime 标记检查配置AutoFailover:true在 Web 页面确认实例没有维护窗口标记切换后从库没有自动指向新主从库曾经人工做过 CHANGE MASTER残留复制信息保险起见先 stop slave; reset slave all; 等 Orch 自动重新配置或者用 move-below 强制重新挂载离线安装时报 RPM 依赖缺失收集依赖时没加 --resolve或者没把 mysql-community-libs 一并拉取重新在有网机器上用 yumdownloader --resolve 收集或者做本地 yum 源后 yum install切换后原主数据比新主新原主宕机前有未同步事务半同步没开高可用场景强烈建议开半同步复制如果已发生数据分叉人工从新主取备份补齐原主数据Web 页面打不开防火墙 3000 端口未放行或 SELinux 拦截放行 TCP 3000临时 setenforce 0 验证生产环境建议在 SELinux 放行 http_port_t这些坑我在不同环境里都遇到过。最典型的其实是主机名解析问题。Orchestrator 在做拓扑发现时会拿 MySQL 实例的 hostname 和 IP 一起识别实例一旦 /etc/hosts 没写好页面里会出现同一个物理机被识别成好几个实例的诡异现象。所以搭建之前先把每台机器的 /etc/hosts 和 MySQL 的 report_host 全部核对一遍能省掉后面一堆排查时间。6. 离线环境补几个生产落地的细节架构和流程跑通之后还想多说几句生产上容易忽视的细节。首先是 Orchestrator 自身的可用性问题。刚才的方案里Orchestrator 只有一份跟着 73 这台从库共存亡。如果 73 挂了控制面就没了MySQL 复制本身不受影响但没人管了。规模稍微大一点的团队我都建议部署三节点 raft 模式。Orchestrator 支持把自身做成 raft 集群三个节点互相投票任何一个节点挂了另外两个还能继续执行故障切换。配置上也就多几个参数RaftEnabled: true、RaftBind、RaftNodes元数据统一放到同一个 MySQL 后端。这个改造不复杂但收益很高。其次是切换完成之后业务侧怎么办。Orchestrator 只负责 MySQL 这一层切到 72 当新主原来的连接池、代理层、VIP 不会自己跟着变。我这里给一个思路在 Orchestrator 的 hooks 里配置一个写脚本的动作切换完成时执行把新主 IP 通知给上层。PostMasterFailoverProcesses: [ bash /usr/local/bin/notify_new_master.sh {{.MasterHost}} {{.MasterPort}} ]脚本里面可以做的事很多SSH 去更新 HAProxy 配置、调 API 让业务连接池重建、发告警通知值班群。总之让 Orchestrator 的切换变成一个真正完整的业务高可用闭环而不是只在数据库内部换了个主。再有就是定期演练。高可用这东西不演练就等于没有。我见过不止一次平时配置得好好的真到故障那天切换失败。原因五花八门账号过期、某台从库磁盘满了、中间某次人工操作用错了命令把复制链搞乱了。每季度做一次故障演练把主库停掉看着它自动切换再恢复加回把这个过程做成脚本化平台化整个团队的信心是完全不一样的。另外提醒一下时钟同步。Orchestrator 对实例的探活依赖网络往返也依赖时间戳判断。节点间时钟偏差大容易出现误判比如明明主库活着却因为心跳太久被判失效。内网环境配置一个统一的 NTP 源所有机器对齐时间是搭建高可用最基础也最容易被忽略的一步。最后再说一个我自己的体会这套流程从敲第一行命令到完整跑通最快可以一天完成难点永远不在安装而在对复制关系的精准掌控。离线、隔离网、复杂网络环境这些都是表象。Orchestrator 帮你把拓扑可视化了故障自动切了但数据库的高可用永远需要一个人守住最后一公里——理解复制原理理解数据一致性边界知道什么情况该信自动化什么情况必须人工介入。能把这层想清楚工具才能真正成为你的得力助手。