数据质量告警经常给出的是“结果异常”,例如ads_order_daily.pay_amt环比下降 40%、某个字段空值率突增、分区产出延迟、指标口径不一致。但真正需要处理的是后续三个问题:异常从哪里来、影响到哪些报表或服务、修复或变更会不会引入新的问题。
在大数据治理体系里,数据质量负责发现“哪里不对”,数据血缘负责回答“为什么不对、影响到谁、改动会波及哪里”。如果只有质量规则告警,却没有血缘关系,排障通常会停留在人工翻 SQL、查调度、问业务的阶段;而当表级、字段级、任务级血缘被系统化采集并形成图谱后,影响分析、链路追踪、变更评估和故障定位就可以从经验判断变成可查询、可解释、可复用的工程能力。
质量发现问题,血缘缩小问题空间。没有血缘时,排障依赖人脑记忆;有血缘时,排障可以从异常字段出发,沿上游找来源,沿下游看影响,结合任务运行状态定位故障点。
二、血缘的三层模型
表级、字段级、任务级血缘解决的是不同粒度的问题。工程落地时不能只做其中一层,否则能力会断裂。
一个简化后的三层血缘图如下:
表级血缘知道ads_order_daily 依赖哪些表;字段级血缘知道pay_amt 、user_cnt 、pay_order_cnt 分别来自哪些字段和表达式;任务级血缘知道这些表由哪些任务产出,以及哪一次运行可能失败或延迟。
三、表级血缘采集
表级血缘是最容易落地、收益也最直观的一层。它的基本结构是:
upstream_dataset ──[produced/consumed by job]──▶ downstream_dataset
常见采集方式可以分为四类:
表级血缘的采集流程通常如下:
<span> 表级血缘采集流程
</span>
┌────────────┐
│ SQL / 配置 │
└─────┬──────┘
<span> │
▼
┌────────────┐ ┌────────────┐
│ 解析输入表 │ │ 解析输出表 │
└─────┬──────┘ └─────┬──────┘
│ │
└────────┬───────────┘
▼
┌────────────┐
│ 规范化命名 │
└─────┬──────┘
│
▼
┌────────────┐
│ 生成边关系 │
└─────┬──────┘
│
▼
┌────────────┐
│ 写入图存储 │
└────────────┘
</span>
这里最容易被低估的是“规范化命名”。如果一个平台把表写成db.table ,另一个平台写成hive://cluster/db/table ,再一个平台写成catalog.db.table ,最后得到的血缘会被拆成多个孤立节点。工程实践中要先建立统一的资产 URN 或 qualified name 规则,再谈血缘准确率。
四、字段级血缘解析
字段级血缘的价值在于解释“某个指标为什么变成这样”。比如ads_order_daily.pay_amt 异常,表级血缘只能告诉你它来自dwd_order_detail 和dws_user_order ,字段级血缘才能进一步说明它来自SUM(pay_amt) ,并受过滤条件status='paid' 、分区条件和币种转换逻辑影响。
以一段 SQL 为例:
<span>CREATE</span> <span>TABLE</span> ads_order_daily <span>AS</span>
<span>SELECT</span>
dt,
<span>COUNT</span>(<span>DISTINCT</span> user_id) <span>AS</span> pay_user_cnt,
<span>SUM</span>(pay_amt) <span>AS</span> pay_amt
<span>FROM</span> dwd_order_detail
<span>WHERE</span> status <span>=</span> <span>'paid'</span>
<span>GROUP</span> <span>BY</span> dt;
字段级血缘可以抽象为:
字段级血缘解析示例
dwd_order_detail.dt ───────────────▶ ads_order_daily.dt
dwd_order_detail.user_id ──COUNT <span>DISTINCT</span>▶ ads_order_daily.pay_user_cnt
dwd_order_detail.pay_amt ───────SUM─────▶ ads_order_daily.pay_amt
dwd_order_detail.status ───<span>FILTER</span>──────▶ ads_order_daily.pay_user_cnt
dwd_order_detail.status ───<span>FILTER</span>──────▶ ads_order_daily.pay_amt
这里有一个关键判断:status 虽然没有出现在 SELECT 输出字段中,但它影响了结果集范围,因此应该作为条件依赖进入字段级血缘。否则当上游status 枚举变更时,系统无法发现它会影响下游支付指标。
字段级解析一般要经过以下步骤:
字段级血缘解析流程
SQL 文本
│
▼
词法 / 语法解析
│
▼
AST 抽象语法树
│
▼
表别名解析、CTE 展开、子查询展开
│
▼
SELECT / JOIN / WHERE / GROUP BY / HAVING 语义分析
│
▼
字段依赖边生成
│
├── 直接映射:<span>a</span><span>.id</span> -> <span>b</span><span>.id</span>
├── 表达式映射:<span>a</span><span>.price</span> * <span>a</span><span>.num</span> -> <span>b</span><span>.amount</span>
├── 聚合映射:SUM(<span>a</span><span>.amount</span>) -> <span>b</span><span>.total_amount</span>
└── 条件依赖:<span>a</span><span>.status</span> -> <span>b</span><span>.total_amount</span>
字段级血缘的难点不在于简单 SQL,而在于复杂工程场景:
字段级血缘不能盲目追求“100% 自动准确”,更稳妥的策略是给每条字段边记录来源与置信度。
五、任务级血缘采集
任务级血缘把“数据如何流动”和“作业如何运行”连接起来。表级和字段级血缘偏静态,任务级血缘偏运行态,它回答的是:哪一个任务在什么时候消费了哪些数据、产出了哪些数据、是否失败、失败原因是什么、它的父任务或上游调度实例是谁。
任务级血缘可以建模为:
任务级血缘事件模型
┌──────────────┐
│ DataJob │
│ dwd_order_etl│
└──────┬───────┘
│ has run
▼
┌──────────────┐
│ Run │
│ <span>run_id</span>=xxx │
│ <span>state</span>=FAILED │
└───┬──────┬───┘
│ │
reads │ │ writes
▼ ▼
┌───────────┐ ┌──────────────┐
│ ods_order │ │ dwd_order │
└───────────┘ └──────────────┘
│
▼
error_message / start_time / end_time / attempt / owner
任务级血缘在故障定位中尤其重要。假设ads_order_daily 质量告警,系统可以沿表级血缘向上查找dws_user_order ,再通过任务级血缘找到最近一次产出该表的任务运行,进而读取状态、日志地址、错误信息和上游任务状态。这样排障路径就从“人工查一圈”变成“沿图查询”。
质量告警驱动的故障定位路径
<span>[质量告警]</span>
ads_order_daily<span>.pay_amt</span> 环比下降 <span>40%</span>
│
▼
<span>[字段级血缘]</span>
pay_amt <- <span>SUM</span>(dws_user_order.pay_amt)
│
▼
<span>[表级血缘]</span>
dws_user_order <- dwd_order_detail <- ods_order
│
▼
<span>[任务级血缘]</span>
job_dwd_to_dws 最近一次运行延迟 <span>38</span> 分钟
│
▼
<span>[定位结论]</span>
上游 dwd_order_detail 分区迟到,导致 dws 聚合输入不完整
这类能力的前提是任务运行、数据产出、质量结果必须共享一套资产标识。如果质量系统用ads_order_daily ,调度系统用project.ads_order_daily ,血缘系统用hive.prod.ads_order_daily ,三者无法自动关联,排障体验会明显下降。
六、采集架构设计
一套可维护的血缘平台通常由采集层、解析层、标准化层、存储层和应用层组成。
采集架构要重点解决四个工程问题。
第一,采集要分静态和动态。静态血缘来自 SQL、配置、代码仓库、dbt manifest 等,适合提前做变更评估;动态血缘来自运行事件、执行计划、Listener、Hook 等,适合还原真实运行链路。
第二,血缘边要保存来源。比如同一条A -> B 的边,可能来自 SQL 解析,也可能来自运行时事件。前者代表“设计上依赖”,后者代表“实际运行时依赖”。两者同时存在时可信度更高;两者冲突时,反而能暴露配置漂移、动态分支或采集缺口。
第三,图存储要支持多跳遍历。DataHub 的血缘读取接口支持 upstream/downstream 方向查询,并可通过max_hops 获取多跳上下游;字段级血缘结果中还包含路径信息。血缘存储不能只服务“直接上下游”,还要支持“从一个字段向下追 3 跳”“找出所有经过某张表的链路”这类查询。
第四,血缘要能版本化。一次 SQL 改动可能改变字段计算逻辑,表结构变更也可能改变下游影响范围。如果只保存最新图,事后复盘很难回答“昨天为什么没问题,今天为什么有问题”。血缘版本可以按任务版本、SQL hash、Schema 版本、运行时间窗口来组织。
七、影响分析
影响分析的目标是回答:如果改动一个表、字段、任务或口径,会影响哪些下游资产和业务。
典型输入包括:
影响分析可以从下游遍历开始:
字段变更影响分析
源字段:dwd<span>_order_</span>detail.pay<span>_amt
│
▼
直接影响:
dws_</span>user<span>_order.pay_</span>amt
dws<span>_shop_</span>order.pay<span>_amt
│
▼
二跳影响:
ads_</span>order<span>_daily.pay_</span>amt
ads<span>_shop_</span>daily.gmv
<span> │
▼
业务影响:
经营日报
店铺分析看板
GMV 预警规则
</span>
工程上建议把影响分为三类:
这类分级很重要。否则一次上游字段改动可能推送几百个下游对象,最后用户会忽略所有通知。
八、链路追踪
链路追踪关注的是“数据从源头到结果经过了哪些节点”。它与影响分析方向相反:影响分析多从上游向下游扩散,链路追踪常从结果向上游回溯。
指标链路追踪:ads_order_daily.pay_user_cnt
ads_order_daily.pay_user_cnt
▲
│ COUNT <span>DISTINCT</span> user_id
│
dws_user_order.user_id
▲
│ 聚合用户订单
│
dwd_order_detail.user_id
▲
│ 清洗订单明细
│
ods_order.user_id
▲
│ Kafka / Binlog 入湖
│
mysql.<span>order</span>.user_id
链路追踪不只是展示路径,还要在路径上附加关键上下文:
这使链路追踪从“画图”变成“排障证据链”。当用户查看某个指标时,系统不仅能展示上游表,还能回答“这个字段是聚合来的、过滤条件是什么、最近哪层开始异常”。
九、变更评估
变更评估最好发生在上线之前,而不是事故之后。一个成熟的流程应该在 SQL 合并、任务发布、字段变更、表下线之前自动触发血缘分析。
变更评估流程
开发提交 SQL / 配置变更
<span> │
▼
解析新旧血缘
│
▼
对比血缘差异
│
├── 新增上游表
├── 删除上游字段
├── 输出字段表达式变化
├── 下游影响范围变化
└── 敏感字段传播变化
│
▼
生成评估结果
│
├── 可直接发布
├── 需要负责人确认
└── 阻断发布
</span>
变更评估要特别关注字段级变化。例如下面这个改动看似只是优化 SQL,但会改变指标口径:
变更前:
<span>SUM</span>(pay_amt) <span>AS</span> gmv
变更后:
<span>SUM</span>(<span>CASE</span> <span>WHEN</span> status <span>=</span> <span>'paid'</span> <span>THEN</span> pay_amt <span>ELSE</span> <span>0</span> <span>END</span>) <span>AS</span> gmv
如果没有字段级和条件依赖血缘,系统只能看到输出字段仍然是gmv ,很难发现口径已经变化。更进一步,如果status 字段被标记为枚举字段,变更评估还应该检查枚举值是否稳定。
十、故障定位
故障定位通常从告警开始,但不能停留在告警本身。一个推荐的定位顺序是:
故障定位四步
<span>1.</span> 定位异常对象
表 / 字段 / 分区 / 指标
<span>2.</span> 查找最近变化
数据质量结果 / Schema / SQL / 任务版本 / 调度时间
<span>3.</span> 沿血缘回溯
字段级优先,表级补充,任务级验证
<span>4.</span> 收敛根因
上游数据异常 / 任务失败 / 延迟产出 / 口径变更 / Schema 漂移
示例:
告警:
ads_order_daily.pay_amt 今日 <span>10</span><span>:</span><span>00</span> 分区金额下降 <span>40</span>%
血缘回溯:
ads_order_daily.pay_amt
<span><-</span> dws_user_order.pay_amt
<span><-</span> dwd_order_detail.pay_amt
<span><-</span> ods_order.pay_amt
任务状态:
job_ods_to_dwd COMPLETE <span>09</span><span>:</span><span>05</span>
job_dwd_to_dws COMPLETE <span>09</span><span>:</span><span>40</span>
job_dws_to_ads COMPLETE <span>10</span><span>:</span><span>02</span>
质量结果:
ods_order.pay_amt 正常
dwd_order_detail.pay_amt 正常
dws_user_order.pay_amt 异常
定位:
异常首次出现在 dws_user_order 层,优先检查 job_dwd_to_dws 的 SQL、分区过滤和聚合逻辑。
如果任务级血缘采集了错误信息,定位还能更快。
十一、落地建议
血缘系统最容易失败的原因不是图画得不漂亮,而是准确率、覆盖率和使用场景没有闭环。建议按以下顺序推进。
第一阶段先做表级血缘,把核心数仓链路接起来。重点不是覆盖所有系统,而是覆盖高价值链路,例如 ODS-DWD-DWS-ADS、核心报表、核心指标和高频变更任务。此阶段的目标是支持基本上下游查询和表下线影响分析。
第二阶段补字段级血缘,优先覆盖核心指标字段。字段级血缘成本更高,不适合一开始追求全域覆盖。建议从财务、交易、用户、风控等关键主题域开始,把高价值字段的计算链路解析清楚。
第三阶段接入任务级运行信息,把血缘和调度、质量、告警打通。表和字段解释“依赖关系”,任务运行解释“本次为什么异常”。只有三者结合,才能支撑故障定位闭环。
第四阶段引入变更评估,把血缘能力前移到研发流程。上线前自动比较新旧血缘、识别下游影响、标记敏感字段传播、通知资产负责人,能显著降低变更事故。
可以用一个成熟度模型描述:
血缘能力成熟度
L0 无血缘
<span> 靠人工查 SQL 和问人
</span>
L1 表级血缘
<span> 能查上下游表,支持基础影响分析
</span>
L2 字段级血缘
<span> 能解释指标字段来源,支持口径核验
</span>
L3 任务级血缘
<span> 能关联运行状态,支持故障定位
</span>
L4 治理闭环
<span> 质量、血缘、变更、权限、告警联动
</span>
本文适合数据治理、数仓研发与SRE团队。核心价值是把血缘从静态图谱推进到变更评估与故障定位闭环,帮助降低上线风险、缩短排障路径。