3. 异步任务编排基础:任务依赖、DAG、工作流引擎与异步执行模型

在分布式系统中,单个业务请求往往需要拆解为多个子任务,这些子任务之间存在明确的执行顺序与数据依赖。异步任务编排正是解决“谁先执行、谁后执行、失败后怎么办”的核心技术。本章从任务依赖关系出发,逐步深入到有向无环图(DAG)、工作流引擎及异步执行模型,为后续基于 OpenTelemetry 的故障排查奠定理论基础。

3.1 任务依赖关系

任务依赖定义了子任务之间的执行约束。常见的依赖类型包括:

依赖类型 说明 示例
顺序依赖 任务 B 必须在任务 A 完成后才能启动 先下载文件,再解压
并行依赖 任务 C 等待任务 A 和任务 B 都完成后才能启动 等待两个数据源都就绪后合并
条件依赖 根据上游任务的输出结果决定下游任务是否执行 若校验失败则跳过后续处理
数据依赖 下游任务需要上游任务的输出数据作为输入 将特征工程的结果传给模型训练
实践要点:在定义依赖关系时,应避免循环依赖。循环依赖会导致任务永远无法完成,是编排系统中最常见的配置错误之一。

3.2 有向无环图(DAG)

DAG 是任务编排的数学基础。它将每个子任务建模为节点,将依赖关系建模为有向边,并保证图中不存在环路。DAG 的核心特性包括:

  • 拓扑排序:总能找到一种线性顺序,使得所有依赖关系得到满足。
  • 并行度:同一层级的无依赖节点可以并发执行。
  • 容错边界:单个节点失败不会影响无依赖的其他分支。

下图展示了一个典型的异步任务 DAG 结构,包含数据采集、预处理、特征工程、模型训练与结果聚合五个阶段:

异步任务 DAG 示例 数据采集 数据预处理 特征工程A 特征工程B 模型训练 结果聚合 并行分支:A 与 B 可同时执行
DAG 与可观测性:在 OpenTelemetry 中,每个 DAG 节点对应一个 Span,节点间的有向边对应 Span 的 Parent-Child 关系。通过 Trace 可以完整还原 DAG 的执行路径与耗时分布。

3.3 工作流引擎

工作流引擎是 DAG 的运行时载体,负责解析 DAG 定义、调度任务执行、处理失败重试与超时。主流的工作流引擎对比:

引擎 语言 状态持久化 重试策略 可观测性集成
Temporal Go / Java / Python 内置 Event History 指数退避 + 最大重试次数 原生 OpenTelemetry
Airflow Python 数据库(PostgreSQL/MySQL) 固定间隔 + 重试次数 需额外配置 exporter
Argo Workflows YAML / Go Kubernetes CRD Pod 级别重启 通过 OpenTelemetry Operator
Celery Python Redis / RabbitMQ 任务级别重试 需手动注入 Trace
选型建议:如果团队已经采用 Kubernetes 生态,Argo Workflows 的 DAG 原生支持与 Operator 模式能降低运维成本;若需要强一致性保证和长时间运行的工作流,Temporal 的 Event Sourcing 架构更为可靠。

3.4 异步执行模型

异步执行模型决定了任务在 DAG 中的具体运行方式。常见的模型包括:

  • 事件驱动模型:任务通过事件总线触发,上游完成后发布事件,下游订阅后执行。适合高吞吐、低耦合场景。
  • 回调模型:每个任务注册回调函数,上游完成后直接调用下游回调。适合任务数量固定、依赖关系明确的场景。
  • Future/Promise 模型:每个任务返回一个 Future,下游通过 .then() 或 await 等待结果。适合编程语言原生支持的异步框架。
  • 状态机模型:工作流引擎维护全局状态,任务执行后更新状态,引擎根据状态转移决定下一步。适合需要持久化与恢复的复杂工作流。

下图对比了事件驱动模型与回调模型在 DAG 执行中的差异:

事件驱动模型 vs 回调模型 事件驱动模型 任务A 任务B 事件总线 任务C 任务D 回调模型 任务A 任务B 任务C 任务D 任务A/B 直接持有下游 C/D 的引用 完成时同步调用回调函数
异步模型与 Trace 传播:在事件驱动模型中,Trace 上下文需要通过消息头传递(如 Kafka Headers 或 RabbitMQ 的 Headers Exchange);在回调模型中,上下文通常通过线程局部变量或协程上下文隐式传递。OpenTelemetry 的 Propagator 组件负责处理这两种场景的上下文注入与提取。

3.5 异步任务编排的故障模式

理解编排基础后,需要提前识别常见的故障模式:

  • 死锁:两个任务互相等待对方释放资源,导致 DAG 永远无法推进。
  • 级联失败:一个任务失败后,其下游所有任务被阻塞或连锁失败。
  • 超时未处理:任务执行时间超过预期,但工作流引擎未设置超时机制,导致资源泄漏。
  • 数据倾斜:并行分支中某个任务处理的数据量远大于其他分支,拖慢整体进度。
排查思路:在后续章节中,我们将利用 OpenTelemetry 的 Span 链路与 Metrics 指标,精准定位上述故障的根因。例如,通过 Span 的 Duration 分布可以快速发现数据倾斜,通过 Span 的 Status Code 可以识别级联失败的传播路径。