跳转至

多主机数据面变更分批与失败阈值 — 规划设计

本文件是规划设计稿,本轮不含代码实现。评审通过后另开一轮实施与实测。

1. 现状与问题

编排入口 deployer.py 的 _run_steps() 目前是「按模块串行、模块内部遍历全部主机」:

# 问题 证据
1 目标格式化(mkfs.lustre)属数据面不可逆动作,却按配置一次性全量下发,无批次、无失败阈值 cmd_bootstrap / cmd_add_oss / cmd_add_ost / cmd_add_mdt 均直接 _run_steps(steps)
2 失败即终止,但半程状态无自动收敛 _run_steps 原文注释:「编排终止于 …(前序模块已变更的不会自动回滚)」
3 无批间健康确认,也无「该主机是否正被调度占用」的批前复核 modules/target_format.py 按主机顺序遍历,无停顿与就绪判定

按 deployment-tool-engineering 的判据:变更落在数据面且不可逆时,未分批即阻断。当前工程处在该阻断状态。

2. 目标

  1. 多主机变更按批次推进,批次规模与批内并发可配置
  2. 批间做健康确认,判定用状态量而非固定 sleep
  3. 失败容忍阈值可配置,超阈值即停后续批次,且「停 / 回滚」由配置决定、不留临场判断
  4. 单主机场景退化为一批,条款同样适用

3. 配置设计(拟新增 rollout 段)

rollout:
  # 数据面变更(mkfs.lustre 等不可逆、清空类动作)
  data_plane:
    batch_size: 1                # 每批主机数;数据面固定逐台,0 视为非法
    max_concurrency: 1           # 批内并发度
    pause_after_batch_sec: 30    # 批间最小停顿,与健康确认共同生效
    failure_threshold: 1         # 允许失败台数,超过即触发 on_threshold_exceeded
    health_gate: true            # 批间是否做健康确认
    on_threshold_exceeded: abort # abort(停后续)| rollback(可恢复项回滚)
  # 控制面变更(服务启停、配置下发等可重入动作)
  control_plane:
    batch_size: 0                # 0 = 不限(一批推完)
    max_concurrency: 5
    pause_after_batch_sec: 5
    failure_threshold: 0
    health_gate: false
    on_threshold_exceeded: abort

config_validate 需同步新增校验:

  • data_plane.batch_size 必须 ≥ 1,填 0 → BLOCK(数据面不允许全量下发)
  • failure_threshold ≥ 0,且不得 ≥ 该批主机数(否则阈值形同虚设)→ WARN
  • on_threshold_exceeded ∈ {abort, rollback},其它值 → BLOCK
  • health_gate: false 且 pause_after_batch_sec: 0 → WARN(等于无批间保护)

4. 实现接入点

4.1 关键取舍:分批的粒度

现有编排是「模块串行、模块内部遍历主机」。若要在「每台主机上跑完整模块链」的意义上分批,需要把编排改成「批次外层循环 × 主机子集」,并要求每个模块支持「仅处理指定主机子集」——多数模块当前从 config_data 自行取主机列表,需要新增 hosts 覆盖入口。这是一次较大的重构。

建议分两步走:

步骤 内容 风险
第一步(先行) 只在含不可逆动作的模块(target_format)内部实现分批 + 阈值 + 批间健康确认;编排层把失败上报即可 低,不动全局编排
第二步(演进) 把编排改为批次外层循环,模块统一支持 hosts 子集参数 中,需逐模块回归

4.2 数据面「回滚」的真实语义

mkfs.lustre 不可逆,磁盘级无回滚手段。因此数据面超阈值后的正确行为是:

  1. 停止后续批次(不做无谓推进)
  2. 输出「已变更 / 未变更」主机清单,标注不可逆项
  3. 对可恢复项(fstab、挂载单元、配置文件)执行回滚
  4. 保留现场,等待人工决策

即 on_threshold_exceeded: rollback 对数据面只能是「停 + 可恢复项回滚」,不能承诺磁盘级回滚。此语义必须写进 SOP 与日志,避免误判。

4.3 批间健康确认(用状态量,不用固定 sleep)

数据面每批完成后的就绪判据:

  • 该批主机的 target 出现在 lctl dl 且状态为 UP(复用 utils/lustre_state.get_online_targets,不另写判据)
  • MDT 侧能通过 lfs df 看到新 target 的容量条目
  • 未就绪则按 pause_after_batch_sec 间隔重试,超过上限即判该批失败

4.4 批前可用性复核

每批开始前复核该批主机是否可动:

  • Slurm:scontrol show node <host> 的 State 不含 ALLOCATED / MIXED,或该节点已 DRAIN
  • LSF:bhosts <host> 无运行作业
  • 任一不满足即把该主机移出本批(不阻塞其它主机),并在报告中标记

5. 验收判据

# 判据 判定方式
1 dry-run 输出按批分组,标注批次号与批内主机 人工核对输出
2 单批失败达阈值后,后续批次未启动 构造失败用例(如某批设备不可用)
3 连续执行两次,第二次零变更、全跳过 幂等复跑
4 批间就绪判定使用状态量,无固定 sleep 代码走查
5 rollout 段字段全部被实现体引用,且有校验 配置校验输出

6. 未决项

  1. 当前拓扑不足以做真实失败演练:只有 1 个 OSS、1 个 MDT,无法验证「批间失败停止」。需先扩到 ≥2 台 OSS,或接受「单主机退化为一批」的降级验证(仅能验证单批失败即停)。
  2. 批次粒度需在实施前定稿:按主机分批(4.1 第一步)还是改为按模块分批。
  3. 阈值语义:用绝对台数还是比例;建议绝对台数(小规模集群更直观),大规模时再引入比例。

来源:/home/rain/Documents/lustre_ins/tuning-fix-and-rollout-plan/batch-rollout-plan.md | 最后更新:2026-09-24 12:43(由 build/sync.py 同步,请勿在站点侧修改)