本章将介绍
- 如何将数据流水线中的工作流表示为任务图
- Airflow 在工作流管理器生态中的定位
- 如何判断 Airflow 是否适合你的场景
企业越来越依赖高质量数据来做数据驱动决策,并优化业务流程。多年来,这些业务流程所涉及的数据量已经显著增长,从“每天数 MB”上升到“每分钟数 GB”。虽然应对这场数据洪流看起来是一项巨大的挑战,但只要采用合适的工具,这些不断增长的数据规模是可以被有效管理的。
Apache Airflow 正是帮助你应对这一挑战的工具之一。它通过构建数据流水线,以高效、结构化的方式协调数据操作。就这个过程而言,Airflow 最适合被理解为一个编排总指挥:它连接你的各类系统,并在它们之间协调工作,以确保最终产出和谐一致的结果——高质量的数据。这些工作可以涵盖非常广泛的操作,从从源系统加载数据,到通过查询进行数据转换,再到训练模型,等等。
读完本书后,你不仅能够使用 Airflow 构建数据流水线,还能够以一种结构化、经过充分思考的方式来使用它。这样一来,你就可以在生产环境中使用 Airflow,以不同方式编排不同类型的工作流。我们会采用动手实践的方式:书中的每一个概念和 Airflow 的每一个组成部分,不仅会通过文字解释,还会配合(真实世界的)示例,方便你映射到自己的实际场景中。
我们先从对 Airflow 中数据流水线的简短介绍开始。接着,我们会讨论在评估 Airflow 是否适合你时需要考虑的几个关键点,并演示如何迈出使用 Airflow 的第一步。
1.1 认识数据流水线
数据流水线通常由若干任务或操作组成,这些任务必须被执行,才能得到期望的结果。假设我们想构建一个小型天气仪表盘,用来展示未来一周的天气情况(见图 1.1)。为了实现这样一个实时天气仪表盘,我们大致需要执行如下步骤:
图 1.1 对于这个天气仪表盘,天气数据会从一个外部 API 拉取,并送入一个动态仪表盘中。
- 从天气 API 获取天气预报数据。
- 对获取到的数据进行清洗或其他转换(例如将温度从华氏度转换为摄氏度,或反过来),以满足我们的用途。
- 将转换后的数据推送到天气仪表盘。
可以看到,这个相对简单的流水线由 3 个任务组成,每个任务完成其中的一部分工作。更重要的是,这些任务需要按照特定顺序执行;例如,在获取数据之前就尝试转换数据显然没有意义。同样,在数据完成所需转换之前,也无法把新数据推送到仪表盘。因此,在运行这一数据处理流程时,我们必须确保这种隐含的任务顺序得到严格执行。
1.1.1 将流水线画成图
让任务之间依赖关系更加显式的一种方式,是把数据流水线画成一张图。在这种基于图的表示方式中,任务被表示为图中的节点,而任务之间的依赖关系则被表示为这些任务节点之间的有向边。边的方向表示依赖方向:若一条边从任务 1 指向任务 2,就表示任务 1 必须先完成,任务 2 才能开始。
把这种图表示法应用到我们的天气仪表盘流水线上,会发现它对整体流水线给出了一种相当直观的表示(见图 1.2)。只需扫一眼这张图,我们就能看到流水线包含 3 个任务,每个任务都对应前面列出的一个步骤。边的方向则清晰地表明了任务的执行顺序;我们只要顺着箭头,就能追踪整个执行流程。
图 1.2 天气仪表盘数据流水线的图表示。节点表示任务,有向边表示任务之间的依赖关系(边从任务 1 指向任务 2,表示任务 1 必须先运行)。
这种图通常被称为有向无环图(directed acyclic graph,DAG) ,因为它既包含有向边,又不包含任何回路或循环(acyclic,无环)。这种“无环”特性极其重要,因为它可以防止我们遇到任务间的循环依赖,例如任务 A 依赖任务 B,同时任务 B 又依赖任务 A(见图 1.3)。一旦尝试执行这样的图,就会出现问题:任务 2 只有在任务 3 完成后才能执行,而任务 3 又只有在任务 2 完成后才能执行。这种逻辑不一致会导致死锁——任务 2 和任务 3 都无法运行,从而使整个图无法执行。
图 1.3 图中的环会因为循环依赖而阻止任务执行。无环图(上)具备清晰的 3 个任务执行路径;而有环图(下)由于任务 2 和任务 3 相互依赖,不再存在清晰的执行路径。
当然,循环图也有其用途,例如可以用来表示算法中的迭代部分——这在很多机器学习(ML)应用中很常见。但它们与 Airflow 所使用的无环图是显著不同的。Airflow 和很多其他工作流管理器,正是利用 DAG 的“无环”特性,来高效地解析并执行这类任务图。
1.1.2 执行一张流水线图
一般来说,DAG 表示法有一个很好的性质:它提供了一种相对直接的算法,用来运行整条流水线。从概念上说,这个算法包含以下步骤:
对于图中每一个尚未完成的任务,执行以下操作:
- 对于每一条指向该任务的边,检查边另一端的“上游”任务是否已经完成。
- 如果所有上游任务都已经完成,就把当前任务加入待执行任务队列。
- 执行队列中的任务,并在它们完成各自工作后将其标记为完成。
- 回到第 1 步,重复以上过程,直到图中所有任务都已完成。
为了看看它是怎么工作的,我们来跟踪一下天气仪表盘流水线的一次小型执行过程(见图 1.4)。在算法第一次循环时,我们会发现 clean 和 push 任务都还依赖尚未完成的上游任务。因此,这两个任务的依赖条件尚未满足,此时还不能加入执行队列。而 fetch 任务没有任何入边,也就意味着它没有未满足的上游依赖,因此可以直接加入执行队列。
图 1.4 利用 DAG 结构按正确顺序执行数据流水线中的任务。图中展示了算法每一轮循环中各任务的状态,以及如何最终完成整个流水线执行(终态)。
在 fetch 任务完成后,我们开始第二轮循环,检查 clean 和 push 任务的依赖。此时 clean 任务可以执行了,因为它的上游依赖(fetch 任务)已经完成,因此可以将它加入执行队列。push 任务此时还不能加入队列,因为它依赖于 clean 任务,而 clean 尚未运行。
在第三轮循环中,当 clean 任务完成后,push 任务终于满足执行条件,因为它对 clean 的上游依赖已经被满足。因此,我们可以将它加入执行队列。当 push 任务执行完成后,就没有更多待执行任务了,整个流水线的执行也随之结束。
1.1.3 流水线图 vs 顺序脚本
虽然把流水线表示为图,能够直观展示流水线中的任务及其依赖关系,但你可能会问:为什么不用一个简单脚本顺序执行这 3 个线性步骤呢?为了说明图表示法的一些优势,我们来看一个稍大一点的例子。
在这个新场景里,一家雨伞公司的老板受到了我们天气仪表盘的启发,希望尝试利用机器学习来提升经营效率。为此,这位老板希望我们实现一条数据流水线,训练出一个把雨伞销量与天气模式相关联的 ML 模型。这个模型可以根据未来几周的天气预报,预测那几周对公司雨伞的需求量(见图 1.5)。
图 1.5 雨伞需求场景概览:利用历史天气数据与销售数据训练模型,以预测未来在不同天气预报条件下的销量需求
为了构建这条模型训练流水线,我们大致需要完成如下步骤:
准备销售数据,包括:
- 从源系统获取销售数据
- 对销售数据进行清洗 / 转换,以满足要求
准备天气数据,包括:
- 从 API 获取天气预报数据
- 对天气数据进行清洗 / 转换,以满足要求
然后:
- 将销售数据集和天气数据集合并,形成一个可作为预测型 ML 模型输入的联合数据集
- 使用该联合数据集训练 ML 模型
- 部署 ML 模型,以便业务方使用
我们仍然可以使用之前相同的图表示法来表示这条流水线:任务画成节点,数据依赖画成边。与前一个例子的重要区别在于,这条流水线的前几个步骤——获取和清洗天气 / 销售数据——实际上是彼此独立的,因为它们处理的是两份不同的数据集。这一点在流水线的图表示中体现得非常清楚:图中有两条独立的分支(见图 1.6),如果我们应用前面的图执行算法,这两条分支就可以并行执行,从而更好地利用可用资源,并有可能比顺序执行任务更快完成整条流水线。
图 1.6 雨伞销量预测模型数据流水线的图表示中,销售任务与天气任务之间的独立性。两组 fetch / clean 任务彼此独立,因为它们处理的是两套不同的数据集(天气和销售)。这种独立性体现在两组任务之间没有边相连。
图表示法的另一个有用性质是:它可以把流水线清晰拆分成多个小而渐进的任务,而不是让一个庞大的单体脚本或进程包揽所有工作。单体脚本乍看之下似乎没什么问题,但一旦流水线中的某个任务失败,就会带来效率低下的问题——因为我们必须重跑整个脚本。相比之下,在图表示中,我们只需要重跑失败的任务(以及它的下游依赖任务)。
1.1.4 使用工作流管理器运行流水线
运行“带有依赖关系的任务图”这一挑战,在计算机领域并不是什么新问题。多年来,已经有许多工作流管理方案被开发出来,用于解决这一问题。一般来说,这些工具都允许你把一张任务图定义并执行为工作流或流水线。表 1.1 列出了一些你可能听说过的知名工作流管理器。
表 1.1 常见工作流管理器及其关键特性
| 名称 | 起源于 a | 工作流定义方式 | 实现语言 | 调度 | Backfilling | 用户界面 b | 安装平台 | 可水平扩展 |
|---|---|---|---|---|---|---|---|---|
| Airflow | Airbnb | Python | Python | 是 | 是 | 是 | Anywhere | 是 |
| Argo | Applatix | YAML | Go | 是 | 否 | 是 | Kubernetes | 是 |
| Azkaban | YAML | Java | 是 | 否 | 是 | Anywhere | N/A | |
| Conductor | Netflix | JSON | Java | 第三方 c | 否 | 是 | Anywhere | 是 |
| Dagster | Elementl | Python | Python | 是 | 是 | 是 | Anywhere | 是 |
| Luigi | Spotify | Python | Python | 是 | 是 | 是 | Anywhere | 是 |
| Make | Bell Labs | 自定义 DSL | C | 否 | 否 | 否 | Anywhere | 否 |
| Metaflow | Netflix | Python | Python | 第三方 d | 否 | 否 | Anywhere | 是 |
| Nifi | NSA | UI | Java | 是 | 否 | 是 | Anywhere | 是 |
| Oozie | Yahoo | XML | Java | 是 | 是 | 是 | Hadoop | 是 |
| Prefect | Prefect Technologies | Python | Python | 是 | 是 | 是 | Anywhere | 是 |
| Temporal | Uber(Cadance) | 多语言 | Go | 是 | 是 | 是 | Anywhere | 是 |
| ControlM | BMC | Python / JSON | 多语言 | 是 | 是 | 是 | Anywhere | N/A |
a 有些工具由某公司(前)员工创建,但这些工具都是开源的,并不代表某一家单一公司。
b 各工具的用户界面质量和功能差异很大。
c github.com/jas34/sched…
d 使用 Argo Workflows 管理。
尽管这些工作流管理器各有优缺点,但它们都提供了相似的核心能力:允许你定义并运行包含多个任务及依赖关系的流水线。其中一个关键差异,在于它们如何定义工作流。例如 Oozie 使用静态(XML)文件来定义工作流:这种方式的工作流可读性较强,但灵活性有限。另一些解决方案,如 Luigi 和 Airflow,则允许你以“代码”的方式定义工作流,这能提供更强的灵活性,但也会更难阅读和测试(当然,这也取决于实现工作流的人本身的编码水平)。
其他关键差异还体现在工作流管理器提供的功能广度上。像 Make 和自定义脚本这类工具,本身并不内置工作流调度能力;如果你想让工作流按固定周期运行,就还需要额外借助 cron 之类的工具。另一些工具则提供了更多增强能力,例如内置监控和友好的 Web 界面,这样你就不必为了这些能力再拼装一堆额外工具。
总的来说,要为你的需求选择正确的工作流管理方案,就必须仔细权衡这些方案的关键特性,并判断它们与你的需求是否匹配。接下来,我们将更深入地介绍 Airflow,并探讨它为何特别适合处理数据导向型工作流或数据流水线。
1.2 认识 Airflow
Airflow 是一个用于开发和监控工作流的开源解决方案。我们先从鸟瞰视角快速了解 Airflow 的核心作用,然后再更细致地分析它是否适合你的具体场景。
1.2.1 用(Python)代码灵活定义流水线
和其他工作流管理器一样,Airflow 允许你把流水线或工作流定义成一个由任务组成的 DAG。这些图与本章前面画过的例子类似:任务定义为图中的节点,任务之间的依赖则定义为节点之间的有向边。
在 Airflow 中,你使用 Python 代码 在 DAG 文件 中定义这些 DAG,本质上就是一些 Python 脚本,用来描述相应 DAG 的结构。Airflow 3 引入了使用 Python 之外其他编程语言的选项。(在 Airflow 3 中已经提供了一个实验性的 Golang SDK。)不过,Python 仍然是 Airflow 的主要语言,而且 Airflow 自身的大多数实现也是用 Python 写的。因此,本书会始终以 Python 作为主语言。
每个 DAG 文件通常会描述某个 DAG 所包含的任务集合,以及这些任务之间的依赖关系,Airflow 会解析这些内容,以识别该 DAG 的结构(见图 1.7)。DAG 文件中通常还会包含一些关于该 DAG 的元数据,用来告诉 Airflow 应该如何、以及何时执行它。关于调度,我们会在 1.2.3 节中进一步展开。
图 1.7 Airflow 流水线通过 DAG 文件中的 Python 代码定义为 DAG。每个 DAG 文件通常定义一个 DAG,其中描述了任务及其依赖关系。DAG 还定义了一个调度间隔,用于决定 Airflow 何时执行该 DAG。
以代码形式定义 Airflow DAG 的一个优势在于,这种编程式方式能为构建 DAG 提供极大的灵活性。正如你在第 12 章中会看到的那样,你可以使用 Python 代码根据某些条件动态生成可选任务,甚至基于外部元数据或配置文件动态生成整张 DAG。这种灵活性使得你在构建任意复杂度流水线时,都能让 Airflow 贴合你的具体需求。
1.2.2 与外部系统集成
除了使用代码定义流水线的灵活性之外,Airflow 基于 Python 的另一个优势在于:任务可以执行任何你能用 Python 实现的操作。随着时间推移,这催生出了大量 Airflow 的外部 provider。这些 provider 使你能够在各种系统之间执行任务,包括外部数据库、大数据技术栈以及各种云服务。借助它们,你可以构建复杂的数据流水线,把分散在多个系统中的数据处理过程串联起来。
1.2.3 调度与执行流水线
当你把流水线的结构定义成 DAG 之后,Airflow 允许你为这个 DAG 定义一个调度规则,以精确决定它何时运行。这样,你就可以告诉 Airflow:让这个 DAG 每小时、每天、每周执行一次,或者使用更复杂的类似 cron 的表达式来定义调度。
为了看看 Airflow 是如何执行 DAG 的,我们先简要了解一下开发和运行 Airflow DAG 所涉及的整体过程。从高层来看,Airflow 主要由 5 个核心组件组成(见图 1.8):
图 1.8 Airflow 中涉及的主要组件包括 API server、scheduler、DAG processor、triggerer 和 workers。
- DAG processor —— 解析 DAG,并通过 Airflow API server 将其序列化后写入 Airflow metastore(元数据数据库)
- Scheduler —— 检查 DAG 的调度规则;如果 DAG 的计划运行时间已到,就开始为 DAG 中的任务安排执行,并把这些任务交给 Airflow workers
- Workers —— 负责接收已被调度执行的任务并真正执行它们。Workers 才是真正干活的部分
- Triggerer —— 对那些支持异步处理的任务检查其完成状态,使 Airflow 能在后台等待某些特定条件成立
- API server —— 作为用户的主要交互入口,用于可视化 DAG,并监控 DAG 运行及其结果。此外,API server 也是其他 Airflow 组件访问 Airflow metastore 的统一网关。所有数据库交互都应通过 Airflow API server 完成
Airflow 的“心脏”大概就是 scheduler 了,绝大多数决定流水线何时、以及如何执行的“魔法”都发生在这里。Scheduler 是一个持续运行的进程,从高层来看,它会反复执行以下步骤(见图 1.9):
图 1.9 使用 Airflow 将流水线开发并执行为 DAG。当用户编写好 DAG 后,DAG processor 和 scheduler 会确保它在正确时机被运行。DAG 运行过程中,用户可以随时监控其进度和输出。
- 当用户把工作流写成 DAG 后,DAG processor 会读取这些包含 DAG 的文件,从中提取相应 DAG 的任务、依赖关系以及调度间隔,并把结果存入 Airflow metastore。
- 对于每一个 DAG,scheduler 会检查自上次检查以来,其调度间隔是否已经到期。如果已经到期,就会把该 DAG 中的任务安排进入执行流程。
- 对于每个被调度的任务,scheduler 会检查它的依赖(上游任务)是否已经完成。如果已经完成,就把该任务放入执行队列。
- 如果某些任务需要依赖外部资源才能完成,其中一部分任务可以被 defer 给 triggerer,这样 workers 就可以腾出来执行那些真正已经就绪的任务。
- Scheduler 跳回第 2 步,开始下一轮循环。
细心的读者可能已经注意到,scheduler 所遵循的步骤与 1.1 节中介绍的算法非常相似。这种相似性并非偶然。Airflow 本质上就是在执行同样的流程,只不过在其上增加了一些额外逻辑,以处理自身的调度语义。
当任务被放入执行队列后,它们会被一组 Airflow workers 取走并并行执行,同时跟踪执行结果。这些结果会通过 API server 回传到 Airflow 的 metastore 中,从而让用户能够通过 Airflow 的 Web 界面(由 API server 提供)查看任务进度和日志。第 3 章和第 4 章会更详细地介绍 DAG 的调度机制。
1.2.4 监控与故障处理
除了调度和执行 DAG 之外,Airflow 还提供了一个功能丰富的 Web 界面,你可以用它查看 DAG,并监控 DAG 运行结果。登录后(见图 1.10),主页面会提供所有 DAG 及其结果的高层概览,以及 Airflow 各组件的整体健康状态(见图 1.11)。
图 1.10 Airflow Web 界面的登录页。在随书附带的代码示例中,默认提供了一个用户名为 airflow、密码也为 airflow 的用户。
图 1.11 Airflow Web 界面的主页,展示所有 DAG 及其近期运行结果的高层概览
当你点击左侧菜单栏中的 Dags 标签时,会看到 Airflow 中所有 DAG 的总览页面(见图 1.12)。在这个页面里,你可以点击某个具体 DAG,进一步查看它的运行信息。
图 1.12 Airflow Web 界面的 Dags 标签页,展示所有 DAG 及其近期运行结果的高层概览
例如,某个具体 DAG 的 graph view(图视图) 会清晰展示 DAG 中的任务和它们之间的依赖(见图 1.13),这与我们本章中已经看到的示意图很类似。这个视图对于理解 DAG 结构(也就是任务之间依赖关系的细节)特别有帮助,同时也适合查看某次具体 DAG run 的执行结果。
图 1.13 Airflow Web 界面中的 graph view,展示单个 DAG 中的任务概览以及任务间依赖关系
Airflow 还提供了一个详细的 grid view(网格视图) ,用来显示该 DAG 当前正在运行以及历史上所有运行的结果(见图 1.14)。从功能上看,这可能是整个 Web 界面中最强大的视图,因为它不仅让你看到 DAG 随时间推移的运行表现,还能帮助你深入排查失败任务,弄清楚问题究竟出在哪儿。
图 1.14 Airflow 的 grid view,展示雨伞销量模型 DAG 的多次运行结果(包括最近运行和历史运行)。列表示 DAG 的一次执行状态,行表示单个任务在多次执行中的状态。颜色(电子书版本中可见)表示对应任务的运行结果。用户还可以点击这些任务方块,查看某个任务实例的详情,或管理其状态,以便让 Airflow 重新运行它。
默认情况下,Airflow 会通过重试机制来处理任务失败:它可以把任务重试若干次(还可以配置每次重试之间的等待时间),这有助于任务从偶发性失败中恢复。如果重试依然无效,Airflow 会把该任务记录为失败,并在相应配置开启时通知你。调试任务失败通常也比较直接:grid view 允许你看清楚到底是哪些任务失败了,并深入查看它们的日志。这个视图还支持清除单个任务的结果,从而重新运行该任务,以及所有依赖该任务的下游任务——这使得你在修改任务代码之后,重新运行相关任务变得非常方便。
1.2.5 增量加载与回填(backfilling)
Airflow 调度语义中一个非常强大的特性是:调度不仅仅是在某些时间点触发 DAG(这点类似 cron),它还会提供关于上一个以及下一个(预期)调度区间的详细信息。本质上,这让你能够把时间切分为离散区间(例如每天、每周等),并让 DAG 针对每个区间分别运行。如果你现在觉得这有些抽象,也不用担心;本书后面会对这些概念做更详细说明。
Airflow 的这种调度区间特性,对于实现高效数据流水线非常宝贵,因为它使你能够构建增量式数据流水线。在这种增量流水线中,每次 DAG run 只处理对应时间段内的数据(也就是该时间段内相对于上一个时间段发生变化的那部分数据,delta),而不是每次都重处理整个数据集。尤其是在处理大数据集时,这能够显著节省时间和成本,因为它避免了对已有结果的昂贵重复计算。
而当这种调度区间能力再与 backfilling(回填) 结合时,就更加强大了。回填允许你对过去曾经发生过的调度区间执行 DAG。这个特性使得你可以非常容易地通过对过去这些调度区间运行 DAG,来创建(或回填)包含历史数据的新数据集。而且,通过清除历史运行结果,你还可以在任务代码变更后,重新执行任何历史任务,从而在必要时轻松地重处理整个数据集。
1.3 何时使用 Airflow
经过这一轮简短介绍之后,我们希望你已经对进一步了解 Airflow 及其关键特性感到兴奋。不过,在继续深入之前,我们还需要探讨一下:为什么你可能会选择 Airflow(以及为什么你可能不会),以确保 Airflow 确实是最适合你的选择。
1.3.1 选择 Airflow 的理由
在前面的章节中,我们已经介绍了若干关键特性,这些特性使得 Airflow 特别适合实现面向批处理的数据流水线。基于这些特性,我们可以总结出以下几类非常适合使用 Airflow 的场景:
- 按固定的时间计划运行复杂工作流
一个很好的例子是每天某个固定时间运行一次的数据摄取工作流。 - 按不规则计划运行复杂工作流,由特定事件触发,而不是由精确时刻触发
很好的例子包括不定期运行的数据传输任务,以及需要在特定节假日运行的工作流。 - 使用预定义的时间区间与数据集交互
这是一个非常强大的概念。Airflow 会把时间区间传递给你的工作流,使你能够把数据切分进离散时间桶中。 - 与各种外部系统集成
Airflow 拥有大量面向不同系统的集成和扩展。由于它基于 Python,如果有需要,你也能相对容易地扩展或定制这些集成。典型例子包括各种数据库系统(如 PostgreSQL)以及云厂商服务(如 Google BigQuery)的集成。 - 将软件工程最佳实践应用到你的工作流中
Airflow 的核心理念之一,就是:由多段软件定义并运行的工作流,本身也是代码。 - 对过往的工作流执行进行回填(backfilling)
这是 Airflow 非常擅长处理的任务,它允许你在代码变更之后轻松重算任意历史数据集。
Airflow 的另一个额外优势是它是开源的,这意味着你可以基于 Airflow 构建自己的工作,而不会被任何供应商绑死。同时,Airflow 已经存在了相当长时间,并且是一个活跃维护中的开源项目,许多知名公司都在生产环境中使用它。它已经被证明能够很好地扩展以支撑企业级负载,并且天生面向生产场景设计。多个公司还提供托管版 Airflow 方案(如果你希望获得额外技术支持的话),这让你在如何运行和管理 Airflow 安装方面具备很高的灵活性。
1.3.2 不选择 Airflow 的理由
尽管 Airflow 功能丰富,但它的一些设计选择也可能使它并不适用于某些场景,包括以下情况:
- 流式流水线(streaming pipelines)
Airflow 的设计核心主要是运行周期性任务或批处理任务,而不是流式工作负载。一个例子是处理网站点击流数据,其中包含用户在网站上的点击事件。Airflow 非常适合以批量方式处理这类数据集,但并不适合实时处理单条事件。 - 几乎没有编程经验的团队
用代码实现 DAG 可能会让人望而生畏。对于这类团队,使用带图形界面的工作流管理器(例如 Microsoft Azure Data Factory),或者使用静态工作流定义,也许会更合理。 - 大型复杂用例
同样,由于 DAG 是用代码实现的,一旦场景变大,代码会很快变得复杂。要想长期保持 Airflow DAG 的可维护性,就必须具备足够的软件工程规范。例如,使用可复用 DAG、任务模块化等做法,都是 Airflow 对软件工程中常见最佳实践(如 DRY —— Don’t Repeat Yourself,和 SRP —— Single Responsibility Principle)的对应体现。
另外,Airflow 主要是一个工作流 / 流水线管理平台,目前并不内置诸如**数据血缘(data lineage)**和 数据版本控制 这类较为完善的特性。如果你需要这些能力,很可能还需要把 Airflow 与其他专门工具组合使用。
注意
Airflow 的较新版本已经支持 OpenLineage(mng.bz/gm9G)。
1.4 本书剩余内容
到这里,我们希望你已经对 Airflow 是什么,以及它的特性如何帮助你实现和运行数据流水线,有了一个较为清晰的认识。在本书第一部分的剩余内容中,我们会介绍 Airflow 的基础组成部分——这些内容是你开始构建自己数据流水线之前必须熟悉的。这个部分的内容适用面较广,也适合更广泛的读者群体。我们假设你具备中等程度的 Python 编程经验(大约一年左右),也就是说,你应当熟悉字符串格式化、推导式、以及 args / kwargs 这些基础概念。同时,你还应熟悉 Linux 终端的基本使用,并对数据库(包括 SQL)和数据格式具备基本工作知识。
在第 2 部分和第 3 部分中,我们将深入介绍 Airflow 的高级特性,例如动态生成 DAG、实现自定义 operator,以及运行容器化任务。这些章节需要读者对相关技术有更深入理解,包括自定义 Python 类、Docker 基础概念、文件格式以及数据分区。我们预计这些部分会特别吸引数据工程师读者。
最后,第 4 部分将聚焦于 Airflow 部署相关主题,包括部署模式、监控、安全以及云架构。我们预计这些章节会特别适合那些负责落地和管理 Airflow 部署的人,例如系统管理员和 DevOps 工程师。
小结
-
DAG 是一种可视化工具,用于表示数据处理流水线中的数据工作流。在 DAG 中,节点表示要执行的任务,边定义了任务之间的依赖关系。与单体脚本相比,这种方式不仅在视觉上更易理解,还能带来更好的结构表达、更容易的调试与重跑能力,以及并行执行的可能性。
-
在 Airflow 中,DAG 是通过 Python 文件定义的。虽然 Airflow 3 引入了使用其他语言的选项,但本书仍然聚焦 Python。这些脚本描述了任务执行顺序及其相互依赖关系。Airflow 会解析这些文件,构建并理解 DAG 结构,从而实现任务编排与调度。
-
尽管市面上已经出现了许多用于执行任务图的工作流管理器,Airflow 仍然有若干关键特性,使其特别适合实现高效的、面向批处理的数据流水线。
-
作为工作流编排工具,Airflow 之所以出色,得益于它直观的设计、强大的调度能力以及可扩展框架。同时,它还提供了丰富的用户界面,用于监控和管理数据处理工作流中的任务。
-
Airflow 有 5 个关键组件:
- DAG processor —— 读取并解析 DAG,把这些 DAG 的序列化结果存入 metastore,供 scheduler 等组件使用
- Scheduler —— 读取 DAG processor 已解析的 DAG,判断其调度区间是否到期,并将对应任务加入执行队列
- Workers —— 执行 scheduler 分配过来的任务
- Triggerer —— 负责执行那些被延迟(deferred)的任务,这些任务通常在等待外部事件或条件
- API server —— 提供可视化和监控 DAG 及其执行状态的用户界面;同时也充当各 Airflow 组件访问 Airflow 内部状态的统一接口
-
Airflow 允许你为每个 DAG 设置调度规则,明确指定流水线应在何时执行。此外,Airflow 还内置了自动处理任务失败的机制。
-
Airflow 非常适合面向批处理的数据流水线,提供了强大的调度能力,可支持规则的、增量式的数据处理任务。另一方面,Airflow 并不适合流式工作负载,也不适合那些 DAG 结构每天都在动态变化的高度动态流水线。