从一次启用操作追到主备就绪
这一篇解决什么问题
页面上的“开启”最终会落到一条跨主机、跨进程的控制链路。理解它的最好方法,是沿着一次操作依次看计划、mTLS、远端安装、安全引导、主节点提交、Agent 候选切换和选举开启。
状态载体
Plan 负责冻结决策,Operation 负责记录阶段、结果和可继续的恢复点。
顺序约束
先建立可信通信,再安装和引导 Standby,最后切 Agent 并开放选举。
失败原则
先读原状态再继续或回退,不用第二笔操作覆盖第一笔操作留下的现场。
config:
target: _self
data:
- name: 状态载体
desc: Plan 负责冻结决策,Operation 负责记录阶段、结果和可继续的恢复点。
bgColor: '#eef6ff'
textColor: '#1f4e79'
- name: 顺序约束
desc: 先建立可信通信,再安装和引导 Standby,最后切 Agent 并开放选举。
bgColor: '#eefaf4'
textColor: '#176b4d'
- name: 失败原则
desc: 先读原状态再继续或回退,不用第二笔操作覆盖第一笔操作留下的现场。
bgColor: '#fff8e8'
textColor: '#79520b'
2
3
4
5
6
7
8
9
10
11
12
13
14
15
单节点 Ambari Server 扩展为 Active/Standby,远比安装第二个 RPM 复杂。新节点需要拿到完全一致的数据库连接、服务配置和安全材料;已有 Agent 要从单地址迁移到候选列表;两台 Server 还要在一个明确时刻从“单机语义”切换到“共享 Lease 语义”。
如果这些动作没有顺序约束,最容易出现三类半成品:Standby 已启动却没有写围栏、Agent 只认识旧地址、主节点已经进入 HA 而新节点尚不能接管。Ambari Plus 因此把启用过程建模成一笔可持久化、可检查、可继续的 Operation,而不是一串临时 SSH 命令。
# 从页面到服务端:先计划,再执行
Server HA 使用独立的 /api/v2/control-plane/ha 资源域。正式的 Server HA 页面通过 /api/v2/control-plane/ha/server 这一层进入预检查、计划和操作接口。这样可以把“用户想开启 HA”与“后端已经开始改变环境”分开。
一次启用大致经过三个对象:
| 对象 | 负责什么 | 是否改变环境 |
|---|---|---|
| Precheck | 收集当前 Server、数据库、Agent、目标主机和任务状态 | 否 |
| Plan | 固化候选节点、入口模式、版本、安全与容量决策 | 否 |
| Operation | 按阶段执行,记录每一步输入、状态、错误与恢复点 | 是 |
页面先展示计划,让使用者在真正执行前看见阻塞项和即将发生的变化。只有计划有效,才允许创建 Operation。后续页面刷新、浏览器断流或 Active 切换,都通过 Operation 标识重新读取状态,不会重新提交整笔启用请求。
# 预检查并不是“ping 一下目标主机”
启用前需要同时证明当前控制面仍然安全、目标节点能承担 Server,以及整个集群处于可变更状态。
# 当前 Server 与集群状态
- 当前节点必须是可写的单节点 Active;
- 没有正在运行的安装、升级、启停等控制任务;
- 没有其他高可用变更持有全局变更锁;
- 当前 Ambari Server 的版本和 release identity 满足 HA 最低要求;
- 当前 Server 主机上的 Ambari Agent 在线且健康。
# 数据库与目标主机
- 使用可被两个 Server 稳定访问的外部数据库端点;
- 目标主机不是当前 Server,且其 Agent 在线;
- 目标主机满足内存、磁盘和运行环境要求;
- 离线仓库中存在与当前 Server 完全一致的目标软件包;
- 主机名使用稳定 FQDN,正反向解析和时间同步正常。
# 入口与安全
- 明确使用两个直连端点,还是接入外部负载均衡;
- mTLS 材料可以安全复用或重新建立;
- Agent 证书校验已具备启用条件;
- 候选节点、Agent 状态探测路径和重连分散参数可生成。
当前默认容量基线
默认规划会检查目标主机至少有 4096 MiB 可用内存和 2048 MiB 可用磁盘,并以最多 500 个 Agent 作为默认容量档位的参考上限。实际生产还要结合服务数量、告警规模、并发任务和 JVM 参数评估。
预检查结果不是一句“通过/失败”,而应指向可以处理的阻塞项。例如版本不一致时要指出期望 release identity;数据库是本地地址时要先迁移外部数据库;目标 Agent 离线时要先恢复 Agent,而不是让安装阶段再报一条模糊的 SSH 错误。
# 一次启用操作的阶段图

图中的六个视觉节点依次对应:规划、mTLS 身份、Standby 安装、Agent 候选、Lease 生效与唯一 Active 就绪。每个阶段的精确完成条件见下表。
| 阶段 | 核心动作 | 完成标志 |
|---|---|---|
| 规划与锁定 | 固化 Plan,获取 HA 变更锁 | 操作对象和入口模式不再漂移 |
| 安全准备 | 准备 mTLS,完成目标主机远端预检查 | 当前单节点 Server 恢复可写,目标环境通过 |
| Standby 建立 | 安装同版本 Server,安全引导配置,以关闭选举方式启动 | 新节点可观察共享状态,但不能竞争 Active |
| 拓扑提交 | 当前 Server 提交 epoch,Agent 执行 PREPARE 与 ACTIVATE | Agent 认识两个候选并通过 TLS 选择 Active |
| 协议生效 | 打开选举,验证唯一 Active 与故障接管 | 主备、入口、Agent 和原 Operation 全部收敛 |
下面逐段拆开看每个顺序为什么不能随意交换。
# 第一步:先把通信身份准备好
第二台 Server 的引导不直接把数据库密码、主密钥或证书内容塞进普通 Ambari 任务。正式通道依赖 Agent 与 Server 之间的双向 TLS,所以启用流程会先确认当前单节点环境已经具备可用的 mTLS。
如果当前环境使用平台管理的 PKCS12 材料,并且证书用途、别名和身份都满足要求,可以复用;自定义或无法确认来源的 keystore 不会被默认为可复制材料。第一次从单节点切换到双向 TLS 时,当前 Server 可能需要一次受控重启,流程会等待它以 SINGLE_ACTIVE 身份恢复后再继续。
这个顺序形成了一条清楚的边界:
- Server 启动前,可以准备配置、数据库连接和首次 mTLS 材料;
- Server 启动后,不再靠临时脚本反复改写路由、替换证书或重装 Agent;
- 后续变更通过正式 API、持久化 Operation 和受校验的 Agent 动作完成。
这样可以避免“页面显示成功,但运行中又被外部脚本改回另一套配置”的状态漂移。
# 第二步:安装 Standby,但先不要启动
目标 Agent 接收远端安装动作后,会再次检查目标主机环境,并安装与当前 Server release identity 完全一致的软件包。只比较大版本号是不够的:两边若来自不同构建,数据库模型、接口或 HA 行为都可能不一致。
安装完成后,目标 Ambari Server 保持停止。此时它还没有数据库配置、主密钥和 HA 身份,启动只会产生一个没有资格参与集群的进程。把“软件已安装”和“节点可启动”拆开,是整个流程的重要安全点。
# 第三步:通过 Agent mTLS 完成安全引导
当前 Active 生成受控的引导包,通过目标主机已经建立的 Agent mTLS 通道发送。目标 Agent 在落盘前会校验:
- 压缩包和清单的大小上限;
- 每个文件的路径,拒绝目录穿越;
- 文件哈希与清单是否一致;
- 文件模式、所有者和目标位置是否合法;
- 目标 Server 是否仍处于停止状态;
- 包内 release identity 是否与计划一致。
通过后才以原子方式安装数据库连接、Server 配置、主密钥和允许复用的证书材料。引导包大小当前限制在 64 MiB,避免把不受控的大文件通过控制通道传输。
不要手工复制敏感文件来“补步骤”
手工 scp 主密钥或 keystore 看起来很快,却绕过了来源、哈希、权限和节点状态校验,也无法被 Operation 准确记录。失败时应修复正式引导阶段并重试,而不是在两台节点上拼出一套无法证明一致性的配置。
# 第四步:Standby 先以“不可选举”模式启动
安全引导完成后,目标 Server 可以启动,但它的选举开关仍然关闭。此时节点会读取共享数据库、观察当前 Lease,并稳定在 Standby;即使发现机会也不会获取 Active 资格。
这相当于先验证四件事:
- 新 Server 能使用同一数据库;
- 节点身份和 HA 配置可以加载;
- mTLS、端口和运行目录没有问题;
- 写围栏确实阻止它处理普通管理请求。
确认这些条件后,当前 Active 才提交新的 HA epoch。epoch 用来标记这是一套已经形成的候选集合,避免旧候选配置与新一轮 HA 拓扑混用。
# 第五步:Agent 候选采用两阶段切换
Agent 从单个 Server 地址切换到 hadoop1.test.com,hadoop3.test.com 这样的候选列表,也不能一步完成。实现上分为 PREPARE 与 ACTIVATE:
| 阶段 | 写入什么 | Agent 行为 |
|---|---|---|
PREPARE | 写入两个候选、状态接口、epoch 和 TLS 校验要求,但 HA 仍关闭 | 继续连接原 Server,配置已具备回退空间 |
ACTIVATE | 打开 ha_enabled,按计划分批重启 Agent | 通过状态探测选择 Active Ready,并记录最新 Term |
SINGLE | 回退或移除成员时恢复单 Server 配置 | 清理 HA 候选语义,回到指定唯一地址 |
两阶段切换避免了配置刚写一半,Agent 就开始连接一个尚未准备好的 Standby。Agent 重启也按照分散窗口执行,减少大集群同时重连带来的压力。
切换后,Agent 侧的关键语义类似下面这样。这里用于核对,不建议手工编辑代替向导:
[server]
ha_enabled=true
ha_candidates=hadoop1.test.com,hadoop3.test.com
ha_status_path=/api/v2/control-plane/ha/agent-status
ha_reconnect_spread_seconds=10
[security]
ssl_verify_cert=1
2
3
4
5
6
7
8
# 第六步:最后才打开选举
只有在 Standby 可观测、主节点已提交 epoch、Agent 已认识两个候选后,流程才打开 Standby 的选举能力。此时两台 Server 正式进入共享 Lease 协议。
这个时刻以后,任何节点失去 Lease 或无法确认数据库状态都必须自我围栏;新 Active 需要先完成状态恢复,才能通过 readiness。单节点向主备的语义切换到这里才真正完成。
# 启用成功不等于故障切换通过
实现层把故障验收作为独立阶段,是因为静态检查无法证明真实接管链路。完整验收至少观察:
- 两台进程同时存活时只有一个 Active Ready;
- 停止当前 Active 后,Standby 获取更高 Term;
- 新 Active 完成恢复后 readiness 才成功;
- Agent 分散重连,且没有同 Term 双 Active;
- 原 Active 恢复后以 Standby 回归;
- 切换前已存在的 Operation 仍按原标识读取;
- 期间没有自动重放写请求。
如果生产窗口暂时不允许自动演练,可以先完成静态启用,但应明确标记“主备已建立,故障接管尚未验收”,并尽快安排维护窗口。两者不能用同一个“完成”状态混在一起。
# 持久化 Operation 怎样支持续跑
每个阶段都把状态和必要结果写入数据库。页面断开并不终止服务端操作;Active 切换后,新节点读取同一 Operation,判断哪些阶段已完成、哪些步骤允许幂等重试。
不同动作的恢复策略并不相同:
| 动作 | 合理的恢复方式 |
|---|---|
| 查询预检查或阶段状态 | 直接重读 |
| 目标软件包已安装 | 校验版本与服务状态后跳过或继续 |
| 安全引导已完成 | 重新校验清单和目标文件,不盲目覆盖 |
| Agent 候选已 PREPARE | 读取标记,继续 ACTIVATE 或执行正式回退 |
| Server 启动请求超时 | 先查进程、角色和 liveness,再决定是否重试 |
| 浏览器提交操作时断流 | 按原 Operation 查询,绝不自动再创建一笔 |
因此幂等不是“同一个命令多跑几次没关系”,而是每一步都有可证明的前置状态、提交标记和恢复判断。
# 失败时怎样保持可恢复
| 失败位置 | 此时通常是什么状态 | 优先处理 |
|---|---|---|
| 预检查不通过 | 环境尚未变更 | 修复版本、数据库、Agent、容量或任务阻塞后重新规划 |
| mTLS 准备失败 | 当前 Server 仍保持单节点语义 | 恢复证书或 Server,确认 SINGLE_ACTIVE 后续跑 |
| 远端安装失败 | 目标 Server 未启动 | 修复仓库/包/权限,按原 Operation 重试 |
| 安全引导失败 | 目标 Server 仍应停止 | 查清单、哈希、权限和证书,避免手工拼接配置 |
| Standby 启动失败 | 当前 Active 继续服务,选举尚未开启 | 修复目标日志与数据库连接,再启动观察节点 |
| Agent PREPARE 部分失败 | Agent 仍以原 Server 为准 | 补齐失败主机,或使用正式 SINGLE 回退 |
| Agent ACTIVATE 部分失败 | 部分 Agent 已使用候选模式 | 依据批次和标记继续收敛,不能整批盲目重放 |
| 选举开启后验收失败 | 主备协议已经生效 | 保持唯一 Active,先恢复失败成员或入口,再重新演练 |
# 源码里的责任边界
下面列出几处适合继续阅读的入口。类名用于帮助二次开发者定位职责,不需要把所有逻辑堆进同一个资源类。
关键实现入口
| 实现 | 主要职责 |
|---|---|
ControlPlaneHaResource | /api/v2/control-plane/ha 资源入口、概览和阶段 API |
ControlPlaneHaPlanningService | 预检查、计划生成、版本/数据库/容量/安全约束 |
ControlPlaneHaCoordinator | Lease 获取与续租、角色转换、自我围栏 |
ControlPlaneHaPromotionService | 新 Term 下的集群、任务、仓库、告警和凭据恢复 |
ControlPlaneHaWriteFenceFilter | 按角色、Ready 和 Term 阻止过期读写 |
ServerHaCandidateSelector | Agent 候选探测、最高 Term 选择和会话确认 |
| Agent HA 配置动作 | PREPARE、ACTIVATE、SINGLE 三阶段配置与重启 |
| 安全引导动作 | mTLS 传输、清单/哈希/路径校验和原子安装 |
我在看这部分实现时,最关注的不是某一个类有多少行,而是每个副作用有没有同时具备四样东西:持久化状态、前置校验、角色围栏和可恢复路径。四者都在,跨主机操作才经得起中断。
# 把源码理解转化为运维判断
当启用页面卡在某个阶段时,可以沿着下面的顺序判断,而不是直接重装:
- 原 Operation 当前停在哪个阶段,是否仍在运行;
- 当前唯一 Active 是谁,Term 和 epoch 是否一致;
- 失败动作发生在 Server 启动前还是启动后;
- 目标主机上的包、配置、证书和进程状态是否与阶段提交标记一致;
- Agent 是单地址、PREPARE 还是已经 ACTIVATE;
- 应该继续、正式回退,还是先恢复唯一 Active。
这条思路能把“开启失败”拆成具体的状态恢复问题,也能避免因为重新点击按钮制造第二笔冲突操作。
# 接着看什么
下一篇回到 Ambari Plus 页面,给出从环境准备、节点选择到切换验收的完整操作路径,并把源码里的检查项翻译成可以逐项执行的清单。
把 Ambari Server HA 稳稳地跑起来
按页面开启主备,并完成角色、Agent、入口和任务恢复验收。
回看唯一 Active 架构
对 Lease、Term、晋升屏障或 Agent 选主仍有疑问,可以回到架构篇。
config:
target: _self
data:
- name: 把 Ambari Server HA 稳稳地跑起来
desc: 按页面开启主备,并完成角色、Agent、入口和任务恢复验收。
link: /v/custom/thoughts/ambari-server-ha/enable/
bgColor: '#eef6ff'
textColor: '#1f4e79'
- name: 回看唯一 Active 架构
desc: 对 Lease、Term、晋升屏障或 Agent 选主仍有疑问,可以回到架构篇。
link: /v/custom/thoughts/ambari-server-ha/architecture/
bgColor: '#eefaf4'
textColor: '#176b4d'
2
3
4
5
6
7
8
9
10
11
12
13