调度系统选型:Airflow vs Dagster vs Prefect
选调度系统,说白了就是选你未来两年的「队友」。队友选得好,每天准点下班;选得不好,半夜爬起来救火。我这些年三个系统都用过,踩过不少坑,今天把真实感受摊开来讲。
先看一张全景图
下面这张图,是我自己梳理的选型决策路径。你跟着它走,基本不会跑偏。
三个选手的基本画像
先别急着看对比表,我先把三个工具的核心气质说清楚。
Airflow:老大哥,生态最全
Airflow 是调度界的「Linux」。2015 年 Airbnb 开源,现在已经是 Apache 顶级项目。我最早接触它是在 2018 年,那时候 Dagster 和 Prefect 还没出生。Airflow 最大的优势是社区和生态——你遇到过的坑,99% 都有人踩过,Stack Overflow 上一搜就有答案。
但它的缺点也很明显:DAG 定义是「静态」的,调试起来比较痛苦。我记得有一次生产环境上一个 DAG 死活不触发,排查了半天,结果是 scheduler 的时区配置和 worker 不一致。这种问题在 Airflow 里太常见了。
Dagster:资产感知,强类型
Dagster 是后来者,2019 年才出来。它最大的创新是「资产感知」——你不再只关心 DAG 跑没跑完,而是关心「这张表有没有更新」、「这个模型有没有产出」。我个人特别喜欢它的类型系统,每个输入输出都可以声明类型,跑之前就能发现类型不匹配的问题。
我在一个金融项目中用过 Dagster,团队里有个新人写错了一个字段类型,Dagster 在编译阶段就报错了,而不是等到凌晨 3 点跑崩了才发现。嗯,这种体验在 Airflow 里是享受不到的。
Prefect:云原生,开发体验好
Prefect 的口号是「Pythonic workflow」。它的 API 设计非常优雅,用装饰器就能定义 DAG,而且支持自动重试、缓存、并发控制。Prefect 2.0 之后更是把开发体验拉满了——你甚至可以在 Jupyter Notebook 里调试 DAG。
不过 Prefect 的社区相对小一些,有些高级功能需要上 Prefect Cloud(付费)。我有个朋友在小公司用 Prefect,后来业务量大了,发现自建 Prefect Server 的稳定性不如 Airflow,又迁回去了。
核心对比表
下面这张表,我建议你收藏。选型的时候拿出来对照一下,基本能筛掉 80% 的选项。
| 对比维度 | Airflow | Dagster | Prefect |
|---|---|---|---|
| 开源协议 | Apache 2.0 | Apache 2.0 | Apache 2.0(核心) |
| DAG 定义方式 | Python 脚本(静态) | Python + 装饰器(动态) | Python + 装饰器(动态) |
| 调度精度 | 分钟级 | 秒级 | 秒级 |
| 依赖管理 | Task 级别 | Asset 级别(强类型) | Task 级别 |
| UI 体验 | 功能全,但老旧 | 现代化,DAG 可视化好 | 现代化,交互流畅 |
| 重试机制 | 内置,配置灵活 | 内置,支持策略 | 内置,自动重试 |
| 缓存 | 需插件 | 内置(基于输入哈希) | 内置(自动缓存) |
| 云原生支持 | K8s Executor | K8s 原生 | Prefect Cloud / Server |
| 社区规模 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 学习曲线 | 中等(运维复杂) | 中等(概念多) | 低(Pythonic) |
| 适合场景 | 大型团队、复杂依赖 | 数据资产密集型 | 中小团队、快速迭代 |
避坑指南:我踩过的三个坑
⚠️ 坑一:Airflow 的时区问题
我曾经有一个 DAG 设置每天 8:00 执行,结果连续三天都在 7:00 跑了。排查了半天,发现是 scheduler 的时区是 UTC,而 DAG 配置里写的是 Asia/Shanghai。Airflow 默认所有时间都是 UTC,你必须在 airflow.cfg 里设置 default_timezone = Asia/Shanghai,并且每个 DAG 也要显式指定 timezone 参数。这个坑,我建议你一开始就规避。
⚠️ 坑二:Dagster 的「过度设计」
Dagster 的概念确实多:Asset、Op、Graph、Job、Sensor、Schedule……我刚开始用的时候,光理解这些概念就花了一周。后来我发现,其实 80% 的场景只需要 Asset 和 Op 就够了。不要一开始就想着把所有概念都用上,否则你的 DAG 会变得非常复杂。记住:简单才是王道。
⚠️ 坑三:Prefect 的「黑盒」问题
Prefect 的自动重试和缓存确实好用,但有时候你根本不知道它为什么重试、为什么缓存命中。我遇到过一个问题:一个 Task 明明失败了,但 Prefect 自动重试了 3 次都失败,最后它把失败结果缓存了,导致后续所有依赖它的 Task 都拿到了错误数据。排查了 2 个小时才发现是缓存策略配置错了。所以,用 Prefect 一定要把日志级别调到 DEBUG,并且定期检查缓存状态。
选型决策树
如果你还在纠结,我建议你按这个顺序问自己三个问题:
- 团队有多少人? 1-5 人 → 优先 Prefect 或 Dagster;5 人以上 → 优先 Airflow。
- 你们最关心什么? 开发体验 → Prefect;数据资产 → Dagster;生态稳定 → Airflow。
- 未来会不会上 K8s? 会 → 三个都支持,但 Dagster 和 Prefect 更原生;不会 → Airflow 更省心。
💡 我的个人建议
如果你是新项目,我建议从 Prefect 或 Dagster 开始。Airflow 虽然成熟,但它的运维成本确实高。我见过太多团队把 Airflow 搭起来之后,花在维护上的时间比写 DAG 还多。当然,如果你团队里已经有 Airflow 专家,那另当别论。
代码示例:同一个 DAG,三种写法
光说不练假把式。下面我用一个简单的 ETL 场景——从 API 拉数据、清洗、入库——分别用三个工具实现。你感受一下风格差异。
Airflow 版本
from airflow import DAG
from airflow.operators.python import PythonOperator
from datetime import datetime
def extract():
# 从 API 拉数据
pass
def transform():
# 清洗数据
pass
def load():
# 写入数据库
pass
with DAG(
dag_id='simple_etl',
start_date=datetime(2024, 1, 1),
schedule='@daily',
catchup=False
) as dag:
extract_task = PythonOperator(task_id='extract', python_callable=extract)
transform_task = PythonOperator(task_id='transform', python_callable=transform)
load_task = PythonOperator(task_id='load', python_callable=load)
extract_task >> transform_task >> load_task
Dagster 版本
from dagster import asset, define_asset_job, Definitions
@asset
def raw_data():
# 从 API 拉数据
return [...]
@asset
def cleaned_data(raw_data):
# 清洗数据
return [...]
@asset
def stored_data(cleaned_data):
# 写入数据库
pass
etl_job = define_asset_job(name='etl_job', selection=[raw_data, cleaned_data, stored_data])
defs = Definitions(assets=[raw_data, cleaned_data, stored_data], jobs=[etl_job])
Prefect 版本
from prefect import flow, task
@task
def extract():
# 从 API 拉数据
return [...]
@task
def transform(data):
# 清洗数据
return [...]
@task
def load(data):
# 写入数据库
pass
@flow
def etl_flow():
raw = extract()
cleaned = transform(raw)
load(cleaned)
if __name__ == '__main__':
etl_flow.serve(name='daily_etl', cron='0 8 * * *')
你看,Prefect 的代码最简洁,Dagster 的资产概念最清晰,Airflow 最传统。选哪个,取决于你的审美和团队习惯。
最后说两句
调度系统选型没有标准答案。我见过用 Airflow 用得飞起的 3 人小团队,也见过用 Prefect 翻车的大厂。关键是你得清楚自己的场景:团队规模、技术栈、运维能力、未来规划。
如果你现在还在犹豫,我建议你三个都搭一个 demo 跑跑。花一天时间,把同一个 DAG 用三个工具实现一遍,哪个顺手就用哪个。毕竟,工具是为人服务的,别为了工具而工具。