3. 任务编排的核心对象与数据模型
在隐私计算平台中,任务编排的本质是把一个复杂的多方计算作业拆解成若干可独立调度、可独立重试、可独立观测的执行单元,再用依赖关系把它们串成一个有向无环图(DAG)。调度器并不理解“联邦学习”或“安全求交”的业务语义,它只认四类核心对象:DAG 本身、任务节点、依赖边、资源描述与元数据。理解这四类对象的数据模型,是后续编写编排模板、排查调度异常、做资源配额管理的基础。
一、DAG:编排的顶层容器
DAG 是整张编排图的顶层对象,它描述“这次作业由哪些节点组成、谁先谁后、整体超时多久、失败后如何处理”。一个 DAG 通常包含以下字段:
dag_id:作业唯一标识,例如psi_train_20240612_001;nodes:节点集合,每个节点是一个任务节点对象;edges:依赖边集合,描述节点之间的先后约束;schedule:调度策略,如手动触发、定时触发、上游事件触发;sla:整体时限与告警阈值,例如 2 小时内必须完成;on_failure:失败策略,如重试次数、是否继续执行无依赖分支、是否回滚中间结果。
DAG 的关键约束是“无环”。如果 A 依赖 B、B 依赖 C、C 又依赖 A,调度器无法确定执行起点,必须在校验阶段直接拒绝。实际平台中,DAG 校验通常发生在提交阶段,校验内容包括:是否存在环、是否存在孤立节点、节点引用的资源是否已注册、依赖边引用的节点 ID 是否都存在。
二、任务节点:最小调度单元
任务节点是调度器实际派发和监控的对象。一个节点并不等于一个进程,它更像一份“执行说明书”,描述“用什么镜像、跑什么命令、输入从哪来、输出到哪去、需要多少资源”。典型字段如下:
node_id: "psi_intersect"
operator: "psi"
image: "registry.local/psi:2.3.1"
inputs:
- from: "data_align.output"
mount: "/data/aligned"
outputs:
- name: "intersection"
path: "/data/intersection"
resources:
cpu: "4"
memory: "8Gi"
gpu: 0
retry:
max_attempts: 2
backoff_seconds: 30
timeout_seconds: 1800
其中 operator 是算子类型,决定平台用哪套运行时去执行;inputs 和 outputs 是节点之间传递数据的契约,也是依赖边能够自动推导的依据;resources 是资源描述,调度器据此做节点放置;retry 和 timeout_seconds 是容错参数。节点状态通常包括 PENDING、QUEUED、RUNNING、SUCCEEDED、FAILED、SKIPPED、UPSTREAM_FAILED,调度器只会在所有上游节点进入 SUCCEEDED 后才把当前节点置为 QUEUED。
三、依赖边:控制流与数据流的双重表达
依赖边描述节点之间的偏序关系。它有两种常见语义:控制依赖(A 成功后才执行 B)和数据依赖(B 的输入来自 A 的输出)。在隐私计算场景中,数据依赖尤其重要,因为跨机构的数据交换必须严格发生在双方节点都就绪之后。一条依赖边通常包含:
from_node/to_node:起点与终点节点 ID;trigger_rule:触发规则,如all_success、all_done、one_success;data_ref:可选,指明传递的是哪个输出端口;condition:可选,条件表达式,例如仅当上游输出行数大于 0 时才继续。
需要特别注意的是,依赖边只表达“先后”,不表达“并行度”。调度器会根据入度为 0 的节点集合同时派发多个任务,因此合理设计依赖边可以显著缩短整体耗时。例如数据对齐与模型初始化互不依赖,就应让它们并行,而不是串成一条链。
四、资源描述与元数据:让调度可解释、可审计
资源描述回答“这个节点需要什么”,元数据回答“这个节点是什么、属于谁、可追溯到哪里”。资源描述一般包括 CPU、内存、GPU、磁盘、网络带宽以及节点亲和性(如必须落在某机构机房)。元数据则包括:
owner:任务归属方,用于权限校验;project_id:所属项目,用于配额统计;data_classification:数据密级,如public、internal、confidential;audit_tags:审计标签,记录数据用途、授权批次;version:编排模板版本,便于回滚与复现。
元数据不是装饰,它直接参与调度决策:密级为 confidential 的节点只能被调度到通过安全认证的计算节点;project_id 用于判断是否超出项目配额;version 用于在失败重跑时锁定同一份模板,避免因模板变更导致结果不可复现。
五、四类对象的关系总览
下面这张图把 DAG、任务节点、依赖边、资源描述与元数据放在同一张结构关系图中,重点表现“DAG 包含节点与边、节点携带资源与元数据、边连接节点并约束执行顺序”这一核心模型。
六、一个可提交的编排片段示例
把上述模型落到实际提交物上,一个最小可用的 DAG 描述(YAML 形式)如下。它包含三个节点、两条依赖边,并为每个节点声明了资源与元数据:
dag_id: fl_train_20240612_001
schedule: manual
sla: {max_duration: 7200, alert_at: 5400}
on_failure: {retry: 1, continue_independent: false}
nodes:
- node_id: data_align
operator: data_align
image: registry.local/align:1.4.0
resources: {cpu: "2", memory: "4Gi"}
metadata: {owner: org_A, project_id: fl_2024, data_classification: internal}
- node_id: psi_intersect
operator: psi
image: registry.local/psi:2.3.1
inputs: [{from: data_align.output, mount: /data/aligned}]
resources: {cpu: "4", memory: "8Gi"}
metadata: {owner: org_A, project_id: fl_2024, data_classification: confidential}
- node_id: train
operator: train
image: registry.local/train:0.9.2
inputs: [{from: psi_intersect.output, mount: /data/intersection}]
resources: {cpu: "8", memory: "16Gi", gpu: 1}
metadata: {owner: org_A, project_id: fl_2024, data_classification: confidential}
edges:
- {from: data_align, to: psi_intersect, trigger_rule: all_success}
- {from: psi_intersect, to: train, trigger_rule: all_success}
提交后,平台会先做 DAG 校验:检查 edges 中引用的节点是否都存在、是否存在环、psi_intersect 的密级为 confidential 时是否有可用的安全计算节点。校验通过后,调度器从入度为 0 的 data_align 开始派发;data_align 成功后,psi_intersect 进入 QUEUED;psi_intersect 成功后,train 才被唤醒。若 psi_intersect 失败且重试 1 次仍失败,则 train 会被置为 UPSTREAM_FAILED,不会空跑。
掌握这四类对象后,后续无论是做依赖边优化、资源配额核算,还是排查“节点一直 PENDING”这类问题,都可以回到数据模型上定位:是上游未成功、是资源不足、是密级路由不满足,还是 DAG 校验阶段就被拒绝。模型清晰,调度行为就可解释、可复现。