1. DAG 基础概念:有向无环图的定义、拓扑排序原理、DAG 在任务调度中的核心价值

1.1 有向无环图的定义

有向无环图(Directed Acyclic Graph, DAG)是图论中的一种特殊结构,由一组顶点(Vertex)和一组有向边(Directed Edge)组成,且图中不存在任何环路。在任务调度与数据传输领域,DAG 是描述任务依赖关系与执行顺序的数学基础。

组成要素 符号表示 调度语义
顶点(Vertex) V = {v₁, v₂, …, vₙ} 一个计算任务、数据转换步骤或管道节点
有向边(Directed Edge) E = {(vᵢ, vⱼ) | vᵢ → vⱼ} vᵢ 必须在 vⱼ 之前完成,数据从 vᵢ 流向 vⱼ
无环约束 ∄ 路径 v₁ → v₂ → … → v₁ 保证调度不会陷入死锁或无限循环
关键性质:DAG 的边方向代表依赖方向,而非数据流方向。在数据传输场景中,边方向通常与数据流方向一致,但在某些反向依赖模式中可能相反。

1.2 拓扑排序原理

拓扑排序(Topological Sorting)是将 DAG 的所有顶点排成一个线性序列,使得对于每条有向边 (u, v),u 在序列中都出现在 v 之前。这是 DAG 调度的核心算法基础。

两种经典实现算法:

  • Kahn 算法(入度法):反复移除入度为 0 的顶点,将其加入排序结果,并移除其所有出边。
  • DFS 后序法:深度优先遍历,在回溯时将顶点压入栈,最终栈的逆序即为拓扑序。
// Kahn 算法伪代码
function topologicalSort(graph):
    inDegree = computeInDegree(graph)
    queue = [v for v in graph.vertices if inDegree[v] == 0]
    result = []

    while queue is not empty:
        u = queue.dequeue()
        result.append(u)
        for v in graph.outNeighbors(u):
            inDegree[v]--
            if inDegree[v] == 0:
                queue.enqueue(v)

    if len(result) != len(graph.vertices):
        throw "Graph contains a cycle"
    return result
工程提示:在分布式调度系统中,Kahn 算法更受欢迎,因为它天然支持并行调度——每次入度为 0 的顶点集合可以同时执行,无需等待全局排序完成。

1.3 DAG 在任务调度中的核心价值

DAG 之所以成为任务调度与数据传输的标准建模工具,源于以下四个核心价值:

  1. 依赖显式化:任务间的先后关系、数据依赖、资源约束通过有向边清晰表达,消除隐式耦合。
  2. 并行度最大化:拓扑排序自动识别无依赖的任务组,调度器可同时调度这些任务,充分利用集群资源。
  3. 容错与重试边界:DAG 的每个顶点是独立的失败域,失败任务仅影响其下游,调度器可精确重试或回滚。
  4. 可观测性:DAG 结构天然支持执行状态追踪、进度可视化、瓶颈分析。
行业共识:Apache Airflow、Apache DolphinScheduler、Google Workflow、AWS Step Functions 等主流调度系统均以 DAG 作为核心抽象。DAG 边界决定了调度系统的表达能力上限。

1.4 DAG 结构示意图

下图展示了一个典型的数据传输 DAG,包含 6 个任务节点和 7 条依赖边,体现分层依赖与并行执行模式:

数据传输 DAG 结构示例 数据传输 DAG 结构示例 数据源采集 清洗任务 A 清洗任务 B 格式转换 数据聚合 合并输出 说明:第2层清洗任务 A 与 B 无依赖关系,可并行执行;第3层格式转换与数据聚合也可并行

1.5 拓扑排序与调度顺序

对上述 DAG 执行拓扑排序,可得到多个合法的执行序列。以下表格展示其中一种典型序列及其并行调度策略:

调度轮次 可执行任务 依赖条件 并行度
第 1 轮 数据源采集 无依赖(入度为 0) 1
第 2 轮 清洗任务 A、清洗任务 B 数据源采集完成 2
第 3 轮 格式转换、数据聚合 各自上游清洗任务完成 2
第 4 轮 合并输出 格式转换与数据聚合均完成 1
边界情况注意:当 DAG 中存在多个入度为 0 的顶点时,调度器必须考虑资源约束(如 CPU 核数、内存上限、网络带宽),不能无限制并行。DAG 边界设计需要同时考虑逻辑依赖与物理资源。

1.6 DAG 与数据传输的天然契合

在数据传输管道中,DAG 的边不仅表示依赖关系,还承载数据语义:

  • 数据血缘:每条边记录数据的来源、转换操作与去向,支撑数据溯源与审计。
  • 增量传输:DAG 支持部分节点增量执行,仅重新计算变更的上游节点,避免全量重跑。
  • 背压传播:当下游节点处理速度低于上游时,DAG 结构允许背压信号沿边反向传播,实现流量控制。
总结:DAG 为任务调度提供了数学上严谨、工程上可扩展的建模框架。理解 DAG 的拓扑性质与调度语义,是设计高效、可靠数据传输系统的第一步。