本节摘要:Airflow 的术语不是词典游戏,而是调度器、执行器、界面三方共用的对象名。DAG 是蓝图,DagRun 是某个数据窗口的一次运行,TaskInstance 是该窗口里某个任务的状态机,Operator 是任务“做什么”的实现类型。分不清这四层,排障时就会对着绿色 DAG 卡片问“为什么入库没跑”。
阅读完本节,你应当能够:
把 Airflow 比作一座每天开工的装配车间。图纸挂在墙上,不会因为今天没开工就消失——那是 DAG。今天这一班对应“6 月 2 日零点到 6 月 3 日零点”这批零件——那是 DagRun。这一班里“校验”这个工位有没有做完——那是 TaskInstance。工位上用的是扳手还是焊枪——那是 Operator 类型。
原文把 DAG 说成状态跃迁图谱:节点不是抽象动作,而是带生命周期的计算单元;边不是时间先后的装饰,而是前置条件。无环是语义安全:解析期做拓扑校验,拦住 A 等 B、B 又等 A 的因果死结。你在界面上拖不出环,不是 UI 限制,是调度器拒绝无法收敛的方程。
墙上图纸 DAG │ ├─ 6月2日工单 DagRun │ ├─ 拉数工位实例 │ ├─ 校验工位实例 │ └─ 入库工位实例 └─ 6月3日工单 DagRun └─ 同一套工位,另一批零件
Operator 常被叫成“任务”。严格说,任务是 DAG 里的一个节点(有 task_id),Operator 是这个节点选用的执行模板:PythonOperator 跑函数,BashOperator 跑命令,PostgresOperator 提交 SQL。同一 Operator 类可以实例化出很多任务。Hook 更下一层,封装对外部系统的连接,Operator 内部通常通过 Hook 拿 Connection。开会时有人说“加一个 Postgres 任务”,你要追问:新节点,还是给已有节点换算子。
| 术语 | 现场一句话 | 生命周期 |
|---|---|---|
| DAG | 图纸,可暂停 | 随代码版本变化,不是一次运行 |
| DagRun | 某一数据窗口的工单 | 从 queued/running 到 success/failed |
| Task | 图纸上的一个工位名 | 属于 DAG 定义 |
| TaskInstance | 某张工单上该工位的实际施工 | 有 state、try_number、日志 |
| Operator | 这个工位用什么工具干活 | 类,随任务实例化 |
| Hook | 工具怎么连到外部系统 | 运行时按 conn_id 取凭证 |
TaskInstance 的状态不是装饰色。常见集合包括 none、scheduled、queued、running、success、failed、up_for_retry、upstream_failed、skipped。原文把 Scheduler 称作状态守门人:它扫元数据库,检查依赖是否满足,把实例推进到 queued,交给 Executor;Executor 真正拉起进程或 Pod 后,再把 running/success/failed 同步回去。所以你看见长时间 queued,先问执行器槽位和池配额,不要先改业务 SQL。
upstream_failed 经常被当成“我的任务写错了”。其实它只是说:默认触发规则要求上游全成功,上游已经失败,我按契约不跑。要让清理任务在失败后仍执行,那是 trigger_rule 的事,放到第 2 章。skipped 常见于分支算子切走另一条路,或上游跳过沿触发规则传播。
DagRun 也有自己的状态。一次运行成功,意味着这次窗口里被调度到的任务按规则走完;并不证明蓝图在所有窗口都正确。补数跑出来的失败,和今晚计划跑出来的失败,要分开看 execution 窗口,不要混在一张“昨天 DAG 红了”的工单里。
调度器还有一组你在界面上会碰到、但不属于任务链的词。is_paused 是全局暂停,直接决定还要不要为它生成新运行。标签用于过滤和权限分组。schedule 在元数据里决定下一个窗口怎么算。原文列出的 DagModel 关键字段还包括文件位置、是否子 DAG、最近解析时间。导入错误不是状态机的一环,而是解析阶段就没能把图纸挂上墙。
现场第二类混淆发生在“东西放哪”。
Connection 是外部系统坐标:主机、登录、额外 JSON。密码应进密钥后端,不要写进 DAG。任务通过 conn_id 引用。Variable 是运行时开关和小型配置,适合表名、批次大小、功能开关,不适合塞整份 JSON 报表。XCom 是任务之间的小纸条,默认进元数据库,只适合短消息:路径、行数、分区名。原文把它定位成轻量信使,不是数据总线。Pool 是命名槽位,限制同时跑的重任务数,例如同一套数据库只允许两个回填。
| 抽屉 | 适合放 | 不适合放 |
|---|---|---|
| Connection | 主机、认证、引擎类型 | SQL 文本、业务开关 |
| Variable | 小配置、开关 | 兆字节级结果集 |
| XCom | 路径、计数、分区键 | 整表、模型文件 |
| Pool | 并发配额 | 权限与密码 |
Web 界面上的“任务日志”对应某一次 try 的输出。重试会新增 try_number,旧日志还在。排障时要看失败那一次 try,而不是成功的第一次。SLA 是窗口级承诺:任务或运行超过约定时长会记 SLA miss,它不是超时杀进程;真正杀进程的是 execution_timeout。两个词经常被值班同学混用,一个记过,一个动手。
Sensor 是一类特殊任务:自己不生产数据,只等待外部条件。等到了才成功,超时则失败或重试。它占用 Worker 槽位——传统传感器在 poke 间隔里仍占着人。可延迟算子把等待从 Worker 线程里卸掉,这是第 5 章的主题,但术语上你现在就要知道:等待也是任务,也会出现在图上。
Dataset(较新的数据感知调度)把“上游表写完”从时间表里拆出来:下游 DAG 可以声明消费某个数据集,上游任务更新该数据集后触发。它没有取消 DAG 和 DagRun,只是多了一种触发原因。先把时间窗口模型吃准,再加数据集,否则你会同时用两套钟。
权限相关的词:Role、DAG 级访问、Connection 密码是否可读。原文强调早期默认偏信任内网,生产必须关掉“谁都能进来的公开角色”。术语上先记住:能打开 UI 不等于能触发生产 DAG,能看连接不等于能读明文密码。细节在第 5 章。
最后补一个常被忽略的词:Provider。它不是 DAG,是一组官方或社区维护的 Operator/Hook/Sensor 包,用来对接云存储、数仓、消息队列。你 import 失败时,先问是不是 Worker 环境没装对应 Provider,而不是怀疑调度器坏了。
对照现场的口诀可以压成一句:先锁定窗口,再锁定工位,再问工具和抽屉。 窗口是 DagRun,工位是 TaskInstance,工具是 Operator,抽屉是 Connection/Variable/XCom/Pool。四个对准了,日志才读得懂。
找一次已经结束的 DagRun,按下面顺序指认,指不全就还没把术语内化。第一,DAG 卡片上的名字是蓝图,暂停开关作用在蓝图上,不是作用在某一天。第二,运行列表里每一行是一个窗口,逻辑日期或数据区间写在行上。第三,点进运行后每一行任务是 TaskInstance,注意 map_index 列:没有映射时是空,有映射时必须带上。第四,点开日志看到的是某一次 try。第五,若任务是 PostgresOperator,类型列写的是 Operator,不是“SQL 任务”这种口头词。
Connection 在 Admin 菜单里,不在 DAG 图上。图绿了只说明节点被调度过,不说明连接抽屉里有东西。Variable 也一样。XCom 有单独查看入口,排障时若下游抱怨“没拿到路径”,先看上游这次实例有没有 push 成功,再看 pull 的 task_ids 是否写错。Pool 占用能在界面看到槽位,queued 而池满时,状态机是对的,加机器没用,要等槽或改池。
SLA 与 timeout 再强调一次。SLA miss 可以和 success 同时出现:活干完了,但晚于合同。timeout 是杀这次执行。值班同学把两者都叫“超时”,工单会派错人。前者找为什么计算变长或窗口是否该改,后者找为什么卡死在外部 API。
⚠️ 常见坑:对着 DAG 卡片说“流程挂了”。卡片是蓝图,挂的是某一个窗口里的某一个实例第几次 try。
💡 关键直觉:先锁定窗口,再锁定工位,再问工具和抽屉。四个对准了,日志才读得懂。
最好不。Hook 不出现在图上,不占依赖边。你加一个“Snowflake Hook”并没有增加任务。要增加节点,必须有 Operator 或 TaskFlow 任务。Hook 只在 execute 内部被调用。混着说会导致有人以为“已经接上数仓”,其实只是在某个函数里 new 了客户端,连 conn_id 都没有,密钥治理完全绕开。
它是触发原因和血缘上的一等公民,但没有取消 DagRun 模型。下游被数据集唤醒,仍然创建一个 DagRun,里面仍有 TaskInstance。先把四层(蓝图、运行、实例、算子)说顺,再把数据集当成“另一种建 Run 的理由”。否则会把数据集理解成一种新的执行器。
工单标题禁止只写“Airflow 挂了”。改为:某 dag_id、某窗口、某 task_id、第几次 try、当前状态。接单人据此决定看导入错误、看池、看日志还是看连接。状态词也禁止口语化成“卡住”。queued、running、up_for_retry、upstream_failed 四选一。口语会把池满和函数死循环说成同一个词,于是两人同时重启两个不相关的进程。术语是为了减少同时重启。Sensor、Dataset、Provider 在工单里当修饰语,不要当主语替代实例。主语永远是某一窗口的某一个实例。
none 或尚无:实例未创建,先问 Run 有没有。scheduled:调度器已看见,还没入队。queued:放行了,等执行器槽位或池。running:进程或 Pod 声称在干活,要确认心跳。success:这次 try 正常结束,不保证 SLA。failed:这次 try 失败,看是否还会 retry。up_for_retry:合同允许再试,不要人工再触发同一窗。upstream_failed:自己可能没跑,锅在上游或规则。skipped:分支或规则认为不该跑,不一定是故障。把这张表印在值班室。有人说“卡住”时,逼他选一个词。选不出来就一起打开实例页,直到选出。术语训练靠逼问,不靠本章背诵。Operator 与 Hook 的差别也靠逼问:图上有没有多一个节点。没有节点就没有任务,只有某次 execute 内部的一次会话。会话失败会表现为任务失败,但你不能把 Hook 写进依赖边。边只连任务。连不上的东西,用 conn_id 表达,不用工位表达。
把“昨天流程挂了赶紧重启一下”改写成:dag_id 某日报、窗口为某日、validate 第 2 次 try 为 failed,load 为 upstream_failed,池未满,导入无错误。改写完成后,动作从重启变成看校验日志。这就是术语的全部用处。用处不在考试,在少重启。少重启则少幽灵。少幽灵则 3.2 的执行器看起来更稳。稳往往不是执行器变好了,是词变准了。词准了,人不再拿错刀。拿错刀才会把稳的系统砍出洞。洞再补,监控会记一次失败。失败率上升,信任下降。信任下降后,所有状态词都会被重新翻译成“卡住”。翻译一回归口语,本章前功尽弃。所以工单标题检查要持续,不能只在培训周做。培训周很短。口语很长。用标题格式对抗口语。对抗要写进值班制度,不写进感想。感想没有强制力。格式有。有人标题不达标就打回,直到达标。打回几次,词就会自己变准。变准以后,1.2 才算进了肌肉。肌肉比笔记可靠。笔记会丢。肌肉在夜班还在。
下一节用对照表划清 Airflow 该接哪些流水线、哪些该留给队列和流系统。