数据契约不是文档规范,是调度规范:一次“小改动”引发的三下游事故
一个电商的订单团队在凌晨 02:00 产出事实表,三个下游消费:BI 的日 GMV 大盘、营销的复购预测模型、推荐系统的用户购买力特征。某天,订单团队上线“信用分期”功能,给支付方式字段加了一个新枚举值“installment”,没有人通知下游,因为在每个生产者心里这都是“小改动”。
三个下游的反应很有代表性。BI 大盘把 installment 落进 unknown 桶,分期 GMV 凭空消失,周报数据错了三天才被发现。复购模型把 installment 当成空值,触发兜底分支,给分期用户推全价券,亏损 12 万。推荐 Agent 看到陌生值,自由发挥说“installment 用户偏好高客单”,实际正好相反,推荐点击率跌了 18%。复盘会得出的结论是“以后要通知下游”——这种话写一万次都不会有人执行。真正能阻断这类事故的,是把“通知”翻译成代码、把代码挂进调度。
数据契约的常见误解是把它当成一份 YAML 文档,写完归档就完事。但一份合同的真正价值,不在它写得多漂亮,而在它每天凌晨能不能在数据进生产表之前把脏数据拦下来。Open Data Contract Standard(ODCS)v3.1 把合同的四项内容标准化了:Schema(字段名、类型、约束)、质量保障(新鲜度、完整性、准确性)、SLA(时延、可用性)和语义(数据到底意味着什么)。但标准本身不产生约束力,约束力来自合同被接入 CI 和调度。
一个可操作的做法是:把合同放在独立的仓库里,按 domain 分目录;合同变更必须走 PR,CI 检查变更是否属于破坏性变更——新增枚举值算不算破坏性,取决于消费者是否用 SELECT * 还是显式列名,取决于消费者是否对枚举值做了穷举分支。对于破坏性变更,CI 不是简单拒绝,而是要求同时更新消费者的版本或代码,或者给合同升一个 major 版本,让旧消费者继续读旧版本直到迁移完成。调度层在每次数据产出后、写入生产表之前,按合同执行质量检查;检查失败时,数据不进入生产表,而是进入隔离区,同时触发告警。告警的接收者不是“数据团队”这个模糊的群体,而是合同里显式声明的 owner。
这起事故里还有一个容易被忽视的细节:公司并不是没有数据治理工具,Soda 在跑、DataHub 也接着。差别在于契约有没有挂在调度里。前者是“事后三天被业务发现”,后者是“凌晨 02:34 在数据进生产表之前直接拦下来”。工具提供的是可见性,契约提供的是阻断力。可见性让你知道出了问题,阻断力让问题不发生。
数据契约在 2026 年正在从加分项变成核心生产链路的准入门槛,原因不是治理理念进步了,而是下游的消费者变了。当消费者是另一个团队的 BI 看板时,数据错了三天才被发现,损失是可见的、可归因的。当消费者是 Agent 时,Agent 不会“觉得数据不对然后停下来问”,它会基于错误数据自由发挥,而且发挥得越流畅,错误越难被发现。AI 把脏数据的代价放大了,契约是把这个代价提前到生产之前支付的机制。
- 点赞
- 收藏
- 关注作者
评论(0)