OpenLineage 是什么?跨 Spark、Flink、Airflow 的血缘怎么统一采集?
技术点:数据治理
面试怎么回答
传统血缘靠解析 SQL,Spark 代码和 Python 脚本覆盖不到,每个引擎还要单独开发 Hook,而且只有静态关系,没有每次运行的信息。OpenLineage 是一个开放的血缘标准,模型是 Job、Run、Dataset 三个对象,作业运行时发出 START、COMPLETE、FAIL 等 RunEvent,带上输入输出数据集,再通过 Facet 扩展 Schema、列级血缘、行数、SQL 等信息。Spark 加一个 Listener 从执行计划里提取,SQL 和 DataFrame 都能覆盖;Airflow 有官方 Provider,还能把 Task 和它触发的 Spark 作业关联起来;Flink、dbt 也有集成。事件通过 HTTP 或 Kafka 发到 Marquez、DataHub 这类后端。落地关键是各引擎的数据集命名要统一,否则连不上;要统计覆盖率,上报异步不能影响作业,再和 SQL 静态解析互补。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
很多公司的血缘系统只能解析 Hive SQL,Spark 代码作业、Flink 作业、Python 脚本的血缘都是断的。OpenLineage 是 LF AI & Data 基金会下的开放血缘标准,想解决的就是「各个引擎都按同一种格式上报血缘」。面试官问这题,想看你做血缘时有没有想过解析之外的采集方式。
传统血缘采集的问题
- 靠解析 SQL:只能覆盖 SQL 作业,Spark DataFrame 代码、Python 脚本、临时表、动态 SQL 都解析不全;
- 每个引擎单独适配:Hive 用 Hook,Spark 写 Listener,Flink 又是另一套,每个都要自己开发和维护;
- 只有静态关系:知道表 A 产生表 B,但不知道某一次运行读了哪个分区、写了多少行、成功还是失败。
OpenLineage 的模型
OpenLineage 定义了一种标准的事件格式,核心是三个对象:
- Job:一个作业(比如一个 Airflow Task、一个 Spark 应用);
- Run:作业的一次运行,有唯一的 runId;
- Dataset:作业读写的数据集,分成 inputs 和 outputs。
作业在运行过程中发出 RunEvent,事件类型包括 START、RUNNING、COMPLETE、FAIL、ABORT。每个对象都可以挂 Facet(扩展信息),比如 Schema、列级血缘、数据量、SQL 文本、数据质量结果、父作业关系等。
各引擎怎么接入
- Spark:加一个 OpenLineage 的 SparkListener(配
spark.extraListeners),它从执行计划里提取输入输出,不管是 SQL 还是 DataFrame 代码都能拿到,还支持列级血缘; - Flink:通过 Flink 的 JobListener / 新的血缘接口上报 Source 和 Sink;
- Airflow:官方的 OpenLineage Provider,自动从 Operator 里提取血缘,并把 Task 和它触发的 Spark 作业通过父 Run 关联起来;
- dbt:有专门的集成,从 dbt 的元数据里生成事件。
事件发到哪里由 Transport 决定(HTTP、Kafka、文件等),后端可以是参考实现 Marquez,也可以是 DataHub 等元数据平台。
落地时要注意
- 数据集命名要统一:同一张表在 Spark、Flink、Trino 里必须生成相同的 namespace 和 name,否则血缘连不起来;
- 采集覆盖率要验证:某些自定义 Source、UDF、外部系统写入可能提取不到,要做覆盖率统计;
- 监听器不能影响作业:上报要异步,失败不能导致作业失败,大作业的执行计划解析要注意开销;
- 和 SQL 解析互补:OpenLineage 拿运行时血缘,SQL 解析可以在上线前做静态分析,两者结合效果最好。