为什么数仓任务成功了,数据仍然是错的?
沿事故时间线看错误数据如何穿过 ODS、DWD、DWS、ADS 到消费端;先分清「任务执行完成」和「数据正确」,再建立依赖链重做的判断框架。
为什么数仓任务成功了,数据仍然是错的?
2026-10-16 的 ODS_TRANSACTION 分区只到了一大半,接入任务照常执行 SUCCESS;DWD、DWS、ADS 依次加工完成,报表推送和文件投递也把结果装进了消费端。直到业务侧核对时才发现,这个日期的交易数据少了 12%。
每个任务都 SUCCESS,错误数据是怎么穿过整条链路的?
依赖链重做(Reprocessing)
错误数据已经沿血缘与调度依赖传播后,把受影响的已执行任务实例按真实依赖重新执行,并让下游消费恢复一致的恢复动作。重做关注「同一段依赖链再执行一次」,不修改程序结构,也不等于重构。
事故从哪里开始:ODS 分区不完整,但任务照常成功
这次事故的起点不是某个任务报错,而是一批不完整的源数据被当成了完整分区。新接入的商户交易文件在分区覆盖上存在上线缺陷:控制表只登记「文件已到达」,没有登记这个分区的交易明细是否覆盖完整。
接入任务读取到登记信息后执行 SUCCESS;完整性校验任务也只读取控制表,没有对照交易明细做覆盖核对,因此同样 SUCCESS 放行。到这一步为止,平台内部没有任何失败信号——只有数据本身是错的。
- ODS_TRANSACTION 2026-10-16 分区文件已到达并登记,但交易明细只覆盖了一部分。
- 接入任务与完整性校验任务都成功,但校验的证据强度不足以拦住不完整分区。
- 数据质量门禁的讨论见 6-4;任务就绪与业务日期的区分见 5-2。
为什么 SUCCESS 挡不住错误:任务状态的范围比数据正确小得多
任务状态描述的是「这次执行有没有正常结束」。它不负责证明输入完整,也不负责证明输出正确,更不负责证明消费端拿到了正确数据。当上游把一个不完整分区当作正常输入时,下游任务会照常完成加工,因为加工程序本身没有报错。
本次事故里,DWD 明细行数比前一日少 12%,但没有任何行数或覆盖门禁;DWS 的两支汇总和 ADS 报表继续按依赖执行,最终把错误结果发布给消费端。整条链路上每个任务都完成了自己的加工,错误却在逐层扩散。
- SUCCESS = 任务实例执行完成;不等于输入完整、输出正确或交付完成。
- 没有质量门禁时,错误数据会沿血缘链正常传播,不产生任何失败信号。
- 消费端装载结果同样可以 SUCCESS,因为对消费方来说那是一次正常的装载动作。
错误数据是怎么穿过每一层任务的
沿 7 步时间线推进:ODS 文件到达 → 校验缺口 → DWD 明细 → DWS 两支汇总 → ADS 汇合 → 消费端装载 → 事故结论。每一步会揭示当前任务的状态、污染标记与本步证据。
先把影响范围想清楚,再谈重做
确认数据错误之后,第一反应通常是「把出问题的任务再跑一次」。但本例没有任何任务报错,重跑哪个任务并不能回答范围问题。正确做法是把 SQL 读写血缘、实际调度依赖和业务日期 / 分区结合起来,先圈定受影响范围。
判断规则是:一旦某个任务实例 / 分区进入影响范围,已经执行过的受影响任务都要重做,包括 LEFT JOIN 之后实际结果看起来没有变化的场景;尚未首次执行的进入等待,而不是声称已经重做。与本次事故无关的链路不应被误停。
- 影响范围 = SQL 血缘 + 调度依赖 + 业务日期 / 分区的联合判断,不能只看 DAG 可达性。
- 受影响且已执行 → 重做;受影响且未执行 → 等待;无关链路 → 保持运行。
- 血缘影响分析的通用方法见 7-4;Rerun / Backfill 与重做范围的区别见 5-4。
依赖链重做 ≠ 依赖链重构
两个词都常被简称为「重做/重构」,但处理对象和风险完全不同。
把受影响的实例再执行一次
- 对象:已经执行过的任务实例 / 分区。
- 输入:修复并验证通过后的 ODS 数据。
- 程序:使用最新加工程序,不修改程序结构。
- 风险:范围判断、互斥与下游消费恢复。
修改程序或系统结构
- 对象:代码、表结构、调度定义或系统架构。
- 输入:设计决策与变更方案。
- 结果:程序行为或契约发生变化,需要回归验证。
- 风险:兼容性、迁移与上线发布,不属于本专题范围。