为了账号安全,请及时绑定邮箱和手机立即绑定

Apache Airflow 3.0带来真正的事件驱动调度功能

介绍

随着 Airflow 3.0 的发布日期临近,我感到非常激动,不由得对这个正在开发的巨大转变感到兴奋。这个工具一直以来都是我数据工程工作流程中的核心部分,也是我工作的基础。

我最兴奋的就是事件驱动的轮询调度的实现。

以下是一些 Vikram Koka ,Astronomer 的 首席战略官 在最近在伦敦举行的 Airflow 论坛上与我们分享的内容:

我们希望能够在任意时间运行任务。通过数据驱动的调度和数据集,我们让DAG能够基于Airflow单一部署中的数据运行。

我非常激动地告诉大家,随着Airflow 3的发布,我们希望将此扩展为完整的事件驱动调度,使DAG能够根据外部数据系统中的数据运行。

一张表在Snowflake数据库中更新了,S3中新建了一个文件,你的DAG就开始运行了。

我们希望Airflow不仅能在其内部,还能在整个数据生态系统中发挥作用。

像这样的说法让我对这个项目的未来非常乐观,这样的样子。

在这篇博客文章中,我打算表达我对当前系统的不满情绪,并解释新的基于投票的事件驱动调度系统是如何解决这些不满的。

现状

在Airflow的当前状态下,您只能通过传感器或数据感知调度让一个DAG被外部系统触发。

传感器和数据感知调度这两种技术的功能都很有限,经常在使用它们的时候,总是会有点失望的感觉。

我觉得那两种机制还是有点欠缺,一个小改动就能让它们发挥出全部潜力,它们之间就差那么一个连接点,嗯。

SENSORS 感应器

传感器是Airflow中的一种特殊任务类型,设计用来等待特定条件或事件。它们会阻塞DAG的进一步执行,直到满足特定条件。

一个简单的文件上传监控器例子就是,一个等待文件上传至谷歌云存储以继续执行数据管道流程的文件上传监控器。

一个用例

让我们想象一下这种工作流程可能有用的情形。

你在为客户搭建一个BigQuery数据仓库。有一次,客户走到你面前说:“我们自己制作了一些报表,是用电子表格做的,希望能把它们放到BigQuery里,这样可以更方便地进行分析和保存。”

下一步是制定一个简单的流程,把数据从客户处导入到BigQuery中等等。

  1. 客户将定期将数据上传到云存储桶中。
  2. 上传行为将被我们的传感器检测到。
  3. 云存储中的数据将被传输到BigQuery表中。
  4. 文件将被删除以防止数据堆积。

然后可以按照下面的图,把工作流作为Airflow管道搭建起来 ⬇️。

实现这条流程的管道系统

我不太喜欢的几点

虽然这个流程肯定会起作用,但我对它的问题是,DAG本身不是由 GCSObjectExistanceSensor 来触发的,它的执行只是被传感器阻塞,直到条件满足为止,因此需要一个机制来实际启动DAG。

这又带来了另一个问题,运行Airflow管道的标准方法是通过调度,将其绑定到特定的时间表,但是人类并不遵守时间表,就像在这个场景中的客户也很难每天在下午1点之前按时上传报告一样。

虽然 Airflow 有解决这类问题的方法,但我不认为它很优雅。使用ContinuousTimetable来在 DAG 执行完成后重新触发它更合适。

@dag(  
  start_date=日期时间(2023, 4, 18),  
  schedule="持续调度",  
  max_active_runs=1,  
  catchup=False,  
)

这会构建一个非常混乱且容易误解的心理模型,对于不熟悉 Airflow 的用户来说,这个混乱的心理模型一开始很难被察觉。这样做不仅会形成一种错误的心理模型,而且在凌晨 1 点试图找出你的管道为何失败时,这种错误的心理模型是你最不想拥有的东西。

基于数据的调度

Airflow 的文档页面关于[data-aware scheduling]( 数据感知调度 https://airflow.apache.org/docs/apache-airflow/stable/authoring-and-scheduling/datasets.html) 是这样说的:

除了可以按照时间来调度DAGs之外,你还可以在任务更新数据集时调度DAGs。

    from airflow.datasets import Dataset  # 创建一个指向S3存储桶中CSV文件的数据集示例
    example_dataset = Dataset("s3://dataset-bucket/example.csv")  

读完这篇内容后,我的期望一开始提高了,我认为数据感知调度会解决我所有的数据需求问题,但当我继续读下去时,我有些失望了。

Airflow 不做任何假设关于 URI 所表示的数据的内容或位置,并将 URI 当作字符串处理。

这表明Airflow中的数据集实际上并不是真正的数据集,数据感知调度实际上并不真正了解数据。在Airflow中,数据集仅仅是对数据的一个概念性表示,主要用于创建DAG之间的依赖关系,基本上只是让你可以将一个大的DAG拆分成多个较小的DAG,并确保它们依次执行。

    example_dataset = Dataset("s3://dataset/example.csv")

创建一个名为example_dataset的数据集,该数据集位于S3存储桶的路径下。

with DAG(dag_id="producer", …):  
BashOperator(task_id="producer", outlets=[example_dataset], …).
with DAG(dag_id="consumer", schedule=[example_dataset], …):

数据感知调度是怎么回事

这无疑是一个构建数据感知系统的好开端,但这并不是我真正想表达的意思。

缺失的链环

那么如果我们能够将传感器和数据集结合起来,让外部服务能够通知Airflow有关数据集中发生事件的信息呢?

数据驱动调度与传感器的结合

从Airflow 3计划的功能来看,似乎我的愿望实现了,这将以事件驱动调度的方式实现。

事件驱动调度

事件驱动调度的目标是根据外部事件自动更新数据集(Datasets)。轮询调度将作为此功能的驱动力。

基于轮询的调度机制将能够不断监视外部资源的状态。每当外部资源达到给定状态时,数据集会被更新,这听起来很符合我的预期。

比如,如何检测文件是否上传至 GCS 存储桶。

触发器 = GCSFileUpdatedTrigger(gcs_file="<gcs_file_uri>")
数据集 = Dataset("<gcs_file_uri>", watchers=[触发器])
with DAG(  
  dag_id=DAG_ID,  
  schedule=dataset,  
  start_date=datetime(2021, 1, 1),  
  tags=["示例标签"],  
  catchup=False,  
):  
  empty_task = EmptyOperator(task_id="empty_task")  # 链接空任务
  chain(empty_task)

虽然轮询调度确实会带来一定的资源开销,在不断检查外部资源状态时会使用到这些资源,但将这些检查改用异步触发器(而不是单纯的传感器),会使资源的使用增加变得对普通用户来说几乎不可察觉。

本节仅展示官方Airflow 改进提案中的核心信息。若您想深入了解系统是如何运作的,我建议你看看相关文档。

结论部分

我觉得非常兴奋,Airflow 正在从其核心的时间驱动和依赖性驱动的工作流调度器模式转型,以适应和跟上更现代的市场需求,在这种需求下,系统需要能够迅速响应各种来源的外部事件。

这是Airflow社区迈出的一大步,它让我们不禁想象未来会有什么样的发展。

这里有一些资源

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消