数据工程维护组织的派生数据状态:每个数据产物都是源数据、变换逻辑与时间共同决定的结果,并成为下游的输入。源数据不受控、逻辑持续变化、错误被持久化并沿依赖传播,三者使派生状态天然趋向不可信;数据工程的机制都在回答同一个问题——如何让派生状态可约束、可验证、可重建。
数据工程是构建与维护数据系统和流程的工程学科:将来自不受控源系统的原始数据,持续转化为可信、一致、可被下游使用的信息。
组织持续用数的能力是数据工程的长期产出,该产出同时依赖数据治理提供的所有权、标准与制度。
任一数据产物可表示为:
$$ D^{(t)} = f_{v}\left(S^{(\le t)},\ D_{\text{up}}^{(t)}\right) $$
| 符号 | 含义 | 工程属性 |
|---|---|---|
| $S^{(\le t)}$ | 截至时刻 $t$ 的源数据 | 由源系统按其业务目标产生,数据团队无控制权 |
| $f_{v}$ | 版本为 $v$ 的变换逻辑 | 随口径变更、缺陷修复持续演化,且可能追溯生效 |
| $D_{\text{up}}^{(t)}$ | 上游派生产物 | 产物被持久化并复用,依赖关系构成 DAG |
| $t$ | 时间 | 事件时间与处理时间分离,迟到数据使"某时刻的状态"需要显式定义 |
与在线服务的根本差异在于错误的形态:服务的错误多为瞬时的,修复代码即止损;派生状态的错误是持久的,修复代码之后还须修复已产出的状态及其全部下游。"修代码不等于修数据"是数据工程难以直接套用软件交付实践的原因。
| 根本约束 | 不处理时的失效形态 | 工程回应 | 机制要点 | 事实源 |
|---|---|---|---|---|
| 输入不受控:源系统对下游没有义务,其 schema 是未经约定的接口 | schema 漂移与语义静默变化,下游在结构校验通过的情况下产出错误结果 | 约束输入 | 将隐式依赖转为显式接口;接口按生产级用途建立,由消费需求驱动 | 数据集成、数据建模 |
| 错误持久且传播:运行成功不蕴含数据正确,错误产物成为下游输入 | 扩散面随依赖深度放大,发现越晚修复越贵 | 验证输出 | 对数据本身做断言,以消费方可见的交付单元定义可靠性目标;陈旧优于错误,异常时阻断而非继续产出 | 数据质量、数据运维 |
| 逻辑随时间变化:口径变更、缺陷修复、迟到数据要求改写历史 | 历史结果不可解释,重算结果与原结果不一致,修复引入新错误 | 重建状态 | 可复现 = 不可变输入 + 版本化逻辑 + 确定性变换;重跑必须安全(结果幂等),而非被禁止 | 数据处理、数据建模 |
三项机制相互依赖:没有验证,无从知道何时需要重建;没有可重建能力,验证发现的问题只能靠人工修补;没有输入约束,验证与重建会被源端变更持续消耗。
派生状态模型回答"凭什么成立",价值目标回答"优化什么":
持续、低成本地将数据转化为可被组织使用的确定性价值
这一目标拆解为三种成本:
可信的派生状态是三种成本优化的前提,而不是与之并列的另一个目标:状态不可信时,流动越快错误扩散越快,越容易理解则误用越广,协作越密则单点错误的影响面越大——降本努力会放大损失。
| 机制 \ 成本 | 流动 | 理解 | 协作 |
|---|---|---|---|
| 约束输入 | 主:减少源端变更引发的修复与重跑 | 次:字段语义随接口固定 | 主:生产者与消费者的义务显式化 |
| 验证输出 | 次:异常前置拦截,减少返工 | 主:可信度可观察,使用者无需自行核验 | 次:问题定位有共同证据 |
| 重建状态 | 主:故障修复与口径变更的代价可控 | 主:历史结果可按逻辑版本解释 | 次:变更不再需要全员协调停机 |
分层把变化节奏与控制权不同的部分隔离开,由层间接口吸收变化;派生状态的三项机制沿这些接口落位。
分层隔离变化的通用原理与完整逻辑分层见数据架构。本节只回答数据工程的增量问题:每层的变化由谁控制、在哪里被吸收、三项机制由哪一层承担。
| 层 | 核心问题 | 主要变化来源 | 控制权 | 对应数据架构分层 |
|---|---|---|---|---|
| 价值层 | 数据如何产生业务影响 | 业务策略与用例 | 业务方;是数据工程的需求来源,不属于其职责 | — |
| 服务层 | 数据如何被安全、稳定地消费 | 消费方与访问模式 | 与消费方共同约定 | 数据服务层 |
| 处理层 | 数据如何被变换与建模 | 业务口径 | 数据团队;口径决策权归治理 | 语义层 |
| 集成层 | 数据如何进入系统 | 源系统 schema 与接口 | 不受控 | 接入与传输层 |
| 基础设施层 | 存储与计算如何稳定运行 | 存储计算形态、计算引擎、云平台 | 数据团队或平台团队 | 存储层、计算层 |
| 边界 | 隔离的变化 | 接口形态 | 接口被绕过时 |
|---|---|---|---|
| 源系统 → 集成层 | 源端 schema 与语义变更 | 源端接口约定,或防御性摄取 | 源端变更直达模型,下游静默出错 |
| 集成层 → 处理层 | 原始格式与业务语义的差异 | 不可变的原始数据层 | 摄取时混入业务逻辑,口径变更需要重新摄取 |
| 处理层 → 基础设施层 | 计算引擎与存储换代 | SQL、开放表格式等标准接口 | 口径用引擎专有接口实现,换引擎等于重写口径 |
| 处理层 → 服务层 | 内部模型重构 | 稳定的数据服务出口 | 消费方直接读内部表,内部重构即破坏下游 |
"接口被绕过时"一列可用作诊断信号:出现即说明分层只停留在命名上。
| 机制 | 集成层 | 处理层 | 服务层 | 基础设施层 |
|---|---|---|---|---|
| 约束输入 | 主:源端边 | 辅:语义随版本冻结 | 主:消费边 | — |
| 验证输出 | 辅:入口检测结构漂移 | 主:单元级与模型级断言 | 主:按交付单元的端到端验证 | — |
| 重建状态 | 主:原始数据持久保留 | 主:版本化逻辑与结果幂等 | — | 前提:廉价的不可变存储与可重放计算 |
三项机制都跨越多层,但每层承担的部分不同,且都依赖上一节的接口:接口缺失的层,对应机制无处落地。
五层模型描述职责在空间上的划分,生命周期描述一份派生状态在时间上的轨迹:它被产出后仍要被修正,最终要被终结;这两段轨迹决定了派生状态的长期可信度与成本。
生成 → 流动 → 沉淀 → 建模 → 服务 → 反馈修正(回流上游)→ 退役
| 段 | 阶段 | 派生状态的变化 | 划分依据 |
|---|---|---|---|
| 产出 | 生成、流动、沉淀、建模、服务 | 源数据进入系统,逐级派生为可消费的产物 | 建模与其他变换分开:语义建模承担口径一致性,变化节奏慢于变换实现,对应五层模型中"口径归处理层、引擎归基础设施层" |
| 修正 | 反馈修正 | 已产出的状态被重算或更正 | 派生状态的错误是持久的,产出之后必须存在一条回到上游的修正路径 |
| 终结 | 退役 | 原始数据被删除,派生产物被下线 | 只增不减时,存储、计算与验证成本持续累积;合规删除也要求明确的终点 |
修正是一条与数据流方向相反的路径,每一步依赖不同的前置能力:
| 步骤 | 动作 | 依赖 | 失效形态 |
|---|---|---|---|
| 发现 | 识别产出偏离预期 | 验证输出;消费方反馈渠道 | 由消费方先发现,错误已被用于决策 |
| 定位 | 沿依赖回溯根因所在的产物与逻辑版本 | 数据血缘;运行记录 | 依赖人工排查,修复对象找错 |
| 修正 | 修复源端数据或变换逻辑 | 版本化逻辑 | 覆盖旧逻辑,历史结果无法按原口径解释 |
| 重建 | 重算受影响的分区及其全部下游 | 不可变输入、结果幂等;血缘给出影响面 | 只修根节点,下游仍保留错误结果;或重跑造成重复 |
| 通知 | 告知消费方受影响范围与更正时间 | 消费边接口;交付单元定义 | 消费方不知数据已变,系统内外结果不一致 |
| 对象 | 触发 | 派生状态特有的约束 |
|---|---|---|
| 原始数据 | 保留期届满;合规删除请求 | 删除须沿依赖传播到所有派生产物,否则数据在下游残留;删除范围内不再可重建 |
| 派生产物 | 消费方消失或长期无访问;维护与验证成本超过其价值 | 下线前确认无下游依赖,经消费边通知并给出迁移期;直接删除会破坏未登记的消费方 |
约束只说明派生状态为何不可信,三项机制也只给出应对方向;本章展开每项机制成立所依赖的条件、条件被破坏时的失效形态以及投入的取舍。这些条件不随工具更替而改变,可直接用于评估新工具和定位故障。
派生状态的每条依赖边都是一个接口:上游产物是下游的输入,约束输入的机制因此适用于 DAG 的每一条边。两类边的风险最高:
| 依赖边 | 接口失控的形态 | 机制 | 事实源 |
|---|---|---|---|
| 源端边:源系统 → 数据平台 | 直接读取生产库 schema,源系统按业务需要修改结构与语义,下游静默出错 | 由消费需求驱动的源端接口约定,变更前感知影响面 | 数据集成 |
| 消费边:数据平台 → 外部消费方 | 消费方直接依赖内部表,内部重构即破坏下游 | 数据服务:以稳定出口隔离内部实现 | 数据中台 |
接口由三个要素构成,缺一则约束失效:
适用边界:接口约束只对生产级用途建立。探索期数据的价值未经验证,提前约束会把研发成本转嫁给尚不存在的消费方。仅由生产方定义的接口常因生产方不了解下游用途而失效,接口内容应由消费需求驱动、由生产方维护。
任务运行成功只证明代码执行完毕,不证明数据正确;验证必须作用于产出的数据,而非执行过程。验证按范围分三级,每级只能捕获特定类别的错误:
| 范围 | 捕获 | 漏检 |
|---|---|---|
| 单元级:单个变换 | 逻辑缺陷 | 输入漂移、跨阶段的字段假设 |
| 模型级:单个产物 | 粒度、主键、口径约束被破坏 | 上下游语义不一致 |
| 端到端:从源到消费 | 跨阶段的隐含假设失配、交付延迟 | 定位困难,需血缘辅助 |
各阶段分别达标不蕴含端到端正确,可靠性目标因此以消费方可见的交付单元(如某一时间分区的产物)定义。失败按形态处置:
投入按关键产物与用例分级,不追求全量覆盖。质量维度定义见数据质量,监控与告警体系见数据运维,SLO 的通用概念见可观测性。
口径变更、缺陷修复、迟到数据都要求改写已产出的历史,重建能力决定这些修正的代价。可重建依赖四个条件:
| 条件 | 含义 | 破坏时的后果 |
|---|---|---|
| 不可变输入 | 原始数据落地后持久保留、不被改写 | 修正后无法回到原始事实重算 |
| 版本化逻辑 | 口径变更视为逻辑新版本,按生效期区分新旧口径,而非覆盖旧逻辑 | 重算历史时误用新口径 |
| 确定性变换 | 相同输入与逻辑产出相同结果 | 重算结果与原结果不可比 |
| 结果幂等 | 产出以分区为单位整体覆盖,重复执行结果相同 | 重跑导致重复计数或残留状态 |
结果幂等与执行去重是两个概念:执行去重阻止任务重复运行,结果幂等保证重复运行无害;重建依赖后者。
代价与边界:
三项机制的投入随"下游扩散面 × 错误代价"变化,任一机制都存在不值得全量投入的场景:
| 机制 | 采用信号 | 降级信号 | 降级后的替代 |
|---|---|---|---|
| 约束输入 | 产物进入生产级用途;源端变更已引发事故;同一产物有多个消费方 | 探索期;生产方与唯一消费方同属一个团队;源系统为不可协商的第三方 | 防御性摄取:入口处检测结构漂移并隔离异常批次 |
| 验证输出 | 产物服务外部消费方或决策;错误被发现的时间晚于被使用的时间 | 告警长期无人处置或以误报为主;断言维护成本超过其拦截的损失 | 收缩为少量端到端关键断言加异常检测;阻断降为告警 |
| 重建状态 | 口径会追溯变更;存在迟到数据;历史结果用于对外披露或审计 | 变换不确定;全量快照的存储成本超过返工成本;合规要求删除原始数据 | 以可追溯代替可复现:保留逻辑版本与运行记录,修正以更正记录表达而非改写历史 |
降级是对投入强度的调整,不是放弃对应约束:约束依然存在,只是由代价更低的方式承受其后果。
组织规模、协作复杂度与数据使用密度共同推高产物的"下游扩散面 × 错误代价";当它超过实现某项机制的成本时,该机制从缺位转为必需,构成阶段迁移的动力。
| 阶段 | 识别信号 | 机制状态 | 优先投入 | 过早投入的代价 |
|---|---|---|---|---|
| 项目驱动 | 需求逐个交付;口径散落在应用层;问题由消费方发现 | 三项机制缺位,靠人工修补 | 原始数据持久保留;核心产物的端到端验证 | 需求未稳定时建平台或全量接口约束,规范被绕过 |
| 规模化 | 同一指标多处实现、结果不一;修复依赖个人 | 机制靠规范与评审执行 | 口径收敛;高扩散产物的接口约束;重跑安全 | 规范缺少工具卡点,执行成本随人数线性增长 |
| 平台化 | 规范执行成本过高;同类管道重复实现相同机制 | 三项机制成为平台默认能力 | 接口登记、通用断言、安全重跑下沉为平台行为 | 平台先于共识,错误抽象被固化 |
| 联邦化 | 中心团队成为交付瓶颈 | 领域团队自持产物与接口,平台提供机制,中心制定标准 | 领域所有权与统一标准 | 领域团队尚无维护能力时下放,质量责任悬空 |
阶段划分是对多个组织案例的归纳,规模较小或直接采用托管服务的团队可能跳过中间阶段。平台化与联邦化的具体形态见数据中台与数据网格。