题目重点:以 DAG 定义提取、转换和加载作业,分开计划触发、运行租约、任务幂等与输出提交。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练版 Pipeline 是有向无环任务图,各任务读确定的输入分区、产生版本化输出;按计划或手动触发 run。
- 任务可因 worker 崩溃而至少一次执行,因此副作用须按 (pipelineId,runId,taskId,partitionId) 幂等;题目未明确精确一次合同。
- LB/cache/queue 是候选组件,是否需要取决于流量与读取模式;不把题目泛称组件当具体接口。
解题路线
- 控制面存 DAG、版本、调度日历、输入水位、重试策略和并发上限;发布前判环并校验数据分区与权限。
- 触发器创建唯一 runId,只有全部上游任务成功且输入可见的节点才入队;队列事件带任务尝试号,worker 领取租约并周期续约,超时可重新投递。
- 执行层先写临时/版本化输出,再以条件提交指针或 manifest 原子公布;重复尝试只能有一个版本成为本 run 的正式输出。下游只读已提交 manifest。
- 重试区分暂时错误与数据永久错误,指数退避、重试预算与死信/人工处理;补历史数据创建新 run/backfillId,不直接覆盖线上当前水位。
- 资源池按任务类型、租户和优先级隔离,控制并发和数据倾斜;缓存仅存可重复利用的元数据/只读输入,不替代任务状态数据库。
- 观测每个 run 的 DAG 状态、输入输出版本、延迟、重试、队列积压与 data quality;SLAs 从源到表的水位衡量,支持单任务重跑与整段回放。
手动走一遍
A 抽取完成后 B、C 可并行转换,D 加载须等 B、C 正式提交。B worker 写完文件却在提交前崩溃;重试可重复计算,但 D 不会读到未提交临时文件。若 B 已提交而确认消息丢失,重试用 run/task key 发现同一 manifest,不再创建第二份正式输出。
规模与取舍
V 个任务、E 条依赖的拓扑检查 O(V+E);实际作业时间由最慢关键路径和可用 worker 并发决定。调度元数据 O(V+E+运行次数),数据存储取决于分区量、版本保留和回填窗口;题目无具体规模。
易错点与追问
容易失分的边界
- 把消息队列的至少一次投递误称每个 ETL 副作用都恰好一次。
- 下游读取上游未提交的临时文件。
- worker 失联后无租约/超时,任务永久卡住。
- 补数直接覆盖当前产物,无法审计或回滚。
- 只画 LB、cache、queue 方框,没有 DAG 状态与幂等键。
继续深挖
- 依赖上游数据迟到时怎样控制水位和跳过策略?
- 巨大单分区拖慢关键路径时如何拆分?
- 历史回填与实时每日任务共享资源池怎样避免互相挤压?
- 任务代码升级后重跑旧数据用哪个版本?
