跳到内容

12.2 运行时血缘与影响分析:从一条错误指标追到具体版本

报告里的任务完成率突然下降。目录告诉你指标定义和 owner,却不能回答昨夜那次运行到底读取了哪个快照、使用哪版 SQL、是否跳过北境分区。真正排障需要把静态设计与每次执行事实连接起来。

本课目标

  • 区分设计血缘、运行时血缘与字段级血缘;
  • 建模 dataset、job、run、process 与版本关系;
  • 选择解析、引擎事件和显式埋点等采集方式;
  • 用血缘做变更、事件和隐私影响分析。

1. 血缘是一张带时间的图

基本节点包括:

  • dataset:表、文件集合、流、报告或模型输入;
  • job/process:执行转换逻辑的作业;
  • run:某个 job 的一次具体执行;
  • field:列、指标或特征;
  • code/config:SQL、镜像、参数与 schema 版本。

边至少表达 run READ dataset_versionrun WROTE dataset_version。只记录:

text
missions_clean → daily_report

无法判断它描述当前设计、昨天运行还是三年前已退役逻辑,也无法区分重跑和回填。

2. 设计血缘与运行时血缘

设计血缘

来自代码、DAG 和声明配置,回答“按设计会依赖什么”。它能在部署前做变更检查,但动态分支可能没有实际执行。

运行时血缘

来自查询引擎、调度器、计算框架或作业埋点,回答“这次实际读写什么”。它能绑定 run、时间和状态,却可能只覆盖已运行路径。

两者应并存:设计边用于预防,运行边用于证据。差异本身值得告警,例如代码声明读取三张表,生产 run 只读取两张。

3. 一条可审计的运行事件

json
{
  "run_id": "2026-08-03/daily-report/attempt-2",
  "job_id": "analytics.daily-report:v17",
  "started_at": "2026-08-03T06:01:00Z",
  "ended_at": "2026-08-03T06:08:20Z",
  "status": "complete",
  "inputs": [
    {"asset": "missions_clean", "version": "snapshot-2026-08-03T05:55Z"}
  ],
  "outputs": [
    {"asset": "daily_mission_summary", "version": "partition=2026-08-02/run=attempt-2"}
  ],
  "code_version": "git:9f2…",
  "schema_version": "3"
}

生产实现还要处理 start/complete/fail、重试 attempt、幂等事件 ID、乱序到达和访问控制。血缘事件本身也可能泄露表名、字段分类或租户信息。

4. SQL 正则不能可靠解析血缘

用正则提取 FROMJOIN 会在以下情况失效:

  • CTE、嵌套查询和 correlated subquery;
  • quoted identifiers、catalog/schema 和临时视图;
  • MERGEUPDATE、动态 SQL 与宏;
  • UDF 内部读取、外部函数和存储过程;
  • 引擎重写后的实际物理来源。

优先级通常是:

  1. 查询引擎/执行框架提供的结构化计划或事件;
  2. 使用完整 SQL parser 和方言 AST;
  3. 编排器声明的输入输出;
  4. 作业入口/出口显式埋点;
  5. 人工补录并标记置信度。

不同采集器可能产生冲突边。保存来源、置信度和观察时间,不要静默合并成一条“真相”。

5. 字段级血缘需要表达式语义

表级血缘只能说某表受影响。字段级血缘进一步记录:

text
daily.completed_count
  ← count(distinct missions.mission_id)
     where missions.status in COMPLETED_STATUS_SET(v4)

daily.completion_rate
  ← completed_count / eligible_count

直接映射、聚合、条件、常量、UDF 和多输入表达式应区分。若系统只知道“可能来自这些列”,就标注 unknown/indirect,而不是伪造精确表达式。

字段级血缘昂贵,应优先覆盖 CDE、关键指标、敏感字段和高风险模型特征。

6. 影响分析不是简单 BFS 列表

图遍历能找候选下游,但实际优先级还取决于:

  • 边是否当前有效、最近是否运行;
  • 变更的是名称、类型、单位、值域还是历史语义;
  • 下游是否只读未变字段;
  • 资产是实验、内部报告还是外部决策;
  • 是否有缓存、导出、模型和人工副本;
  • owner、SLO、敏感分类和变更窗口。

影响报告应输出路径与证据:

text
changed field → expression → output field → report/model → owner
last successful run / active consumers / severity / confidence

图中有环、别名和重复边,遍历要维护 visited 集并限制版本/时间范围。

7. 三种典型用途

变更前

检查 schema/语义变更,定位活跃消费者,安排兼容窗口和回归样本。

事件响应

从错误输出反向追溯实际 run 与输入版本,再正向查找已污染报告、特征、模型和导出。

隐私与删除

追踪敏感字段的派生、缓存与外发位置。血缘能给候选范围,但不能证明所有副本都已发现;还要结合访问日志、存储扫描和资产清单。

8. 完整性与新鲜度

监控:

  • 生产 runs 发出血缘事件的覆盖率;
  • complete run 是否都有输入、输出和版本;
  • 目录中活跃资产是否有近期边;
  • 设计与运行边差异;
  • 字段级解析失败率和 unknown 表达式;
  • 事件延迟、重复和孤立节点。

血缘缺边会给影响分析虚假的安全感。查询结果应展示覆盖范围和置信度,而不是只画一张漂亮图。

9. 变更门禁

text
[ ] 当前与近期运行时下游已识别
[ ] 关键字段级路径已核对
[ ] 活跃 owner 已确认或收到通知
[ ] 兼容策略与回滚版本已准备
[ ] 回归样本覆盖旧/新语义
[ ] 外发、模型和缓存已纳入
[ ] 未知/低置信血缘已有人工补查

常见误区

  • 表到表箭头就是完整血缘:缺少版本、run 和字段表达式。
  • 解析 SQL 可覆盖所有转换:动态代码与引擎行为需要其他信号。
  • 画出所有下游就完成影响分析:还要按活跃度、字段和业务风险筛选。
  • 血缘能证明删除完成:未接入系统和人工副本仍需其他发现手段。

练习

  1. 为同一 job 的失败、重试和回填写三条运行事件。
  2. 找一个含 CTE、子查询和 UDF 的 SQL,比较正则与 AST 解析结果。
  3. 为完成率指标画字段级表达式血缘,并标出业务规则版本。
  4. 模拟一个单位变化,生成带 owner、活跃度和置信度的影响报告。

小结

可用血缘不是静态箭头,而是带运行、版本、字段语义和证据来源的图。它让变更和事件响应从“可能有关”推进到“哪次运行、哪列输出、哪些活跃决策受到影响”。

下一章讨论 Data Mesh:当领域增多时,如何分散数据责任,又不失去互操作、平台能力和共同治理。

Built with VitePress | Software Systems Atlas