Skip to content

2. 核心思想:DAG、Operator、Executor 与状态机

一句话理解:Airflow 把“工作流”抽象成 DAG(有向无环图),把“工作单元”抽象成 Task,把“任务执行”委托给 Executor,把所有状态存在 Metadata Database 里——理解这四个抽象,就理解了 Airflow 的骨架。

2.1 核心概念全景

DAG (workflow)

    ├─ Task A (Operator instance)
    │     └─ TaskInstance A (一次具体执行)

    ├─ Task B
    │     └─ TaskInstance B

    └─ Task C
          └─ TaskInstance C

DAG Run = 一次 DAG 执行(对应某个 execution_date / logical_date)
TaskInstance = 某个 Task 在某次 DAG Run 中的具体执行

概念对照表

概念含义示例
DAG有向无环图,描述一组 Task 及其依赖ml_training_pipeline
OperatorTask 的模板/工厂,定义“做什么”PythonOperatorBashOperatorKubernetesPodOperator
TaskOperator 的实例,DAG 中的节点preprocess_data
TaskInstance某次 DAG Run 中 Task 的一次具体执行preprocess_data @ 2026-07-01
DAG RunDAG 的一次完整执行ml_training_pipeline @ 2026-07-01
Execution Date / Logical DateDAG Run 对应的逻辑时间2026-07-01 00:00:00
Executor决定 TaskInstance 在哪里执行LocalExecutorCeleryExecutorKubernetesExecutor
XCom任务间数据交换(cross-communication)ti.xcom_push(key='model_path', value=...)

2.2 DAG:用 Python 写工作流

DAG 是 Airflow 的核心抽象。一个最简单的 DAG:

python
from airflow import DAG
from airflow.operators.python import PythonOperator
from datetime import datetime, timedelta

with DAG(
    dag_id="hello_airflow",
    start_date=datetime(2026, 7, 1),
    schedule=timedelta(days=1),
    catchup=False,
) as dag:
    def say_hello():
        print("Hello Airflow!")

    task = PythonOperator(
        task_id="say_hello",
        python_callable=say_hello,
    )

DAG 的关键属性

属性说明
dag_id全局唯一标识
start_dateDAG 首次生效日期
schedule / schedule_interval调度周期,可以是 cron 表达式、timedelta、Dataset
catchup是否补跑 start_date 到当前之间的所有 DAG Run
max_active_runs同一 DAG 并发运行的最大 DAG Run 数
default_args默认参数(如 owner、retries、retry_delay)

依赖表达

Airflow 用位运算表达依赖:

python
with DAG("demo", ...) as dag:
    a = BashOperator(task_id="a", bash_command="echo a")
    b = BashOperator(task_id="b", bash_command="echo b")
    c = BashOperator(task_id="c", bash_command="echo c")

    a >> b >> c      # a → b → c
    [a, b] >> c     # a 和 b 都完成后 c 才执行

2.3 Operator:任务的模板

Operator 是“Task 的类”。Airflow 提供大量内置 Operator,也支持自定义。

常见 Operator

Operator用途
PythonOperator执行 Python 函数
BashOperator执行 Bash 命令
KubernetesPodOperator在 K8s Pod 中运行容器
DockerOperator运行 Docker 容器
SparkSubmitOperator提交 Spark 任务
SnowflakeOperator执行 Snowflake SQL
S3FileTransformOperatorS3 文件转换
EmailOperator发送邮件

Operator vs Task

  • Operator 是类(class),定义“怎么执行”。
  • Task 是 Operator 实例化后的对象,属于某个 DAG。
  • 同一个 Operator 可以在多个 DAG 里创建多个 Task。

2.4 Executor:任务执行的调度器

Executor 决定 TaskInstance 在哪里、以什么方式运行。这是 Airflow 扩展性的关键。

Executor特点适用场景
SequentialExecutor单进程顺序执行默认开发/测试,不能用于生产
LocalExecutor本地多进程/多线程并行单机中小规模
CeleryExecutor基于 Celery + 消息队列分发到多个 worker传统多机扩展
**KubernetesExecutor`每个 Task 启动一个 K8s Pod云原生、弹性扩缩
DaskExecutor基于 Dask 分布式执行Dask 生态
LocalKubernetesExecutorAirflow 2.10+,本地 + K8s 混合混合工作负载
CeleryKubernetesExecutorAirflow 2.10+,Celery + K8s 混合混合工作负载

Executor 选型建议

  • 开发/CI:SequentialExecutor 或 LocalExecutor。
  • 中小规模生产:LocalExecutor(单台大机器)或 CeleryExecutor。
  • K8s 原生/弹性需求:KubernetesExecutor。
  • 混合:Airflow 2.10+ 的多 Executor 能力,把轻量任务放 Local、重任务放 K8s。

2.5 状态机:TaskInstance 与 DAG Run

TaskInstance 状态

状态含义
none尚未调度
scheduledScheduler 已安排,等待资源
queued已放入 Executor 队列
running正在执行
success成功
failed失败
skipped因依赖条件被跳过
upstream_failed上游失败导致无法执行
up_for_retry等待重试
deferred进入 deferrable 状态,等待 Triggerer 唤醒
sensingSensor 正在轮询

状态流转示意:

none → scheduled → queued → running → success

                    ├─ failed → up_for_retry → queued

                    └─ upstream_failed / skipped / deferred

DAG Run 状态

状态含义
queued已排队等待运行
running有 TaskInstance 正在执行
success所有 TaskInstance 成功
failed有 TaskInstance 失败且无法重试

2.6 XCom:任务间数据交换

XCom(cross-communication)是 Task 之间传递小数据的机制。

python
def extract(**context):
    data = {"rows": 1000}
    context["ti"].xcom_push(key="extract_result", value=data)

def transform(**context):
    ti = context["ti"]
    data = ti.xcom_pull(task_ids="extract", key="extract_result")
    print(f"Got {data['rows']} rows")

with DAG("xcom_demo", ...) as dag:
    t1 = PythonOperator(task_id="extract", python_callable=extract)
    t2 = PythonOperator(task_id="transform", python_callable=transform)
    t1 >> t2

XCom 的注意点

  • 默认存储在 Metadata Database(SQLite/PostgreSQL/MySQL),不适合传大对象。
  • Airflow 2.5+ 支持自定义 XCom backend(如 S3、GCS),可传大 payload。
  • 推荐只传元数据(路径、ID、小配置),不要传整个数据集。

2.7 Deferrable Operator 与 Triggerer

传统 Sensor 会占住一个 worker slot 一直轮询,资源浪费。Airflow 2.2+ 引入 Deferrable Operator

  • Task 执行到等待点时,把状态设为 deferred,释放 worker。
  • Triggerer 是独立进程,负责异步监听事件(如 S3 文件到达、外部 API 回调)。
  • 事件发生后,Triggerer 通知 Scheduler 把 TaskInstance 重新置为 scheduled

典型场景:

  • 等待 S3 文件出现(S3KeySensor 的 deferrable 模式)。
  • 等待外部批处理完成。
  • 等待消息队列中的事件。

2.8 Dataset / Asset 调度

Airflow 2.4+ 引入 Dataset 调度(Airflow 3 演进为 Asset):

  • DAG 可以声明自己产生或消费某些 dataset。
  • 当上游 dataset 更新时,自动触发下游 DAG Run。
  • 从“时间驱动”扩展到“数据驱动”。
python
from airflow.datasets import Dataset

my_dataset = Dataset("s3://bucket/output/data.parquet")

with DAG("producer", schedule="@daily", ...):
    task = PythonOperator(
        task_id="generate",
        python_callable=...,
        outlets=[my_dataset],
    )

with DAG("consumer", schedule=[my_dataset], ...):
    ...

本章小结

  • DAG:用 Python 定义的工作流,包含有向无环的 Task 依赖。
  • Operator / Task / TaskInstance:类 → 实例 → 某次具体执行。
  • Executor:决定 TaskInstance 在哪里执行,是扩展性的关键。
  • 状态机:TaskInstance 从 none → scheduled → queued → running → success / failed,支持重试和 defer。
  • XCom:任务间传小数据,默认存在 Metadata DB,大数据用自定义 backend。
  • Deferrable Operator + Triggerer:异步等待不占用 worker slot。
  • Dataset/Asset:从时间驱动到数据驱动的调度演进。

参考来源

Released under CC-BY-SA-4.0 License.