一、数据契约基础:什么是数据契约、为什么需要数据契约、数据契约的核心要素

1.1 什么是数据契约

数据契约,说白了就是数据生产者和消费者之间的一份书面约定。

我习惯把它比作「API 的 Schema 版本」。你调用一个 HTTP 接口,接口文档会告诉你:传什么参数、返回什么结构、字段类型是什么。数据契约干的是同一件事——只不过它针对的是数据管道里的数据集,比如 Kafka 消息、Hive 表、或者数据湖里的 Parquet 文件。

举个例子。你的团队维护一张「用户订单表」,下游有三个数据应用在用。如果没有契约,你某天把 order_amount 从 decimal(10,2) 改成了 string,下游的报表直接崩了。有了契约,这种改动会被提前发现、提前协商。

一句话定义:数据契约 = 数据生产者承诺的 Schema + 消费者依赖的约束 + 双方认可的演化规则。

数据契约不是新概念。我在 2018 年做实时数仓时,团队就自己搞了一套「字段变更审批流程」。那时候还没人叫它数据契约,但本质是一样的——谁改 Schema,谁负责通知所有人。

1.2 为什么需要数据契约

你可能会问:没有契约,数据不也能跑吗?

能跑,但代价很大。我见过太多这样的场景:

  • 数据生产者默默加了个字段,消费者完全不知道
  • 消费者发现字段 null 值变多了,查了半天才发现上游改了默认值
  • 两个团队因为字段类型不一致,互相扯皮两周

数据契约要解决的核心问题就三个:

问题 没有契约的后果 有契约的解决方式
Schema 变更不可控 消费者无感知,生产事故频发 变更前通知所有订阅方,协商窗口期
数据质量无标准 空值、类型错误、边界值没人管 契约里写明约束条件,自动校验
团队协作成本高 靠口头沟通,信息不对称 契约即文档,所有人看到同一份约定

我个人觉得,数据契约最大的价值不是技术,而是建立信任。生产者敢改,消费者敢用,中间有契约兜底。

我曾经踩过的坑:有一次我们升级了订单表的字段精度,从 decimal(10,2) 改成 decimal(12,4)。自测没问题,上线后下游的金额汇总报表全错了——因为他们的 ETL 脚本里写死了两位小数。如果当时有数据契约,这种问题在评审阶段就能发现。

1.3 数据契约的核心要素

一个完整的数据契约,至少包含以下 5 个要素。我按重要程度排了个序:

  1. Schema 定义——字段名、类型、是否必填、默认值
  2. 语义约束——字段的业务含义、取值范围、枚举值列表
  3. 兼容性规则——哪些变更算兼容、哪些算破坏性变更
  4. 生命周期——数据保留时长、过期策略、归档规则
  5. 责任边界——谁是生产者、谁是消费者、变更通知方式

来看一个实际的数据契约示例。这是我在项目中用过的简化版:

{
  "dataset": "user_order",
  "version": "1.2.0",
  "producer": "订单中心",
  "consumers": ["数据仓库", "实时风控", "BI报表"],
  "schema": {
    "order_id":     { "type": "string",  "required": true,  "description": "订单唯一标识" },
    "user_id":      { "type": "string",  "required": true,  "description": "用户ID" },
    "amount":       { "type": "decimal", "precision": 12, "scale": 2, "required": true },
    "status":       { "type": "enum",    "values": ["pending","paid","shipped","cancelled"], "required": true },
    "created_at":   { "type": "timestamp", "required": true }
  },
  "compatibility": "backward",
  "notification": "邮件+飞书群,提前3个工作日"
}

嗯,这里要注意:兼容性规则是契约里最容易忽略、也最容易出问题的部分。我习惯把兼容性分成三类:

兼容类型 含义 举例
向后兼容 新 Schema 能读旧数据 新增一个可选字段,旧消费者不受影响
向前兼容 旧 Schema 能读新数据 消费者按旧字段读取,忽略新增字段
完全兼容 双向兼容,新旧互读 只增加可选字段,不修改已有字段类型

你想想看,如果契约里只写了 Schema,没写兼容性规则,那演化的时候还是得靠人拍脑袋。我建议每个契约必须明确标注兼容性策略,这是避免「改一个字段炸一片」的关键。

我的经验:刚开始推行数据契约时,别追求完美。先让生产者和消费者把 Schema 和兼容性规则写清楚,其他要素可以逐步补充。契约是活的,不是一次写完就锁死的。

1.4 数据契约的落地形态

数据契约不只是一份文档。在实际工程中,它通常以三种形态存在:

  • 代码形态——用 Protobuf / Avro / JSON Schema 定义,放在 Git 仓库里管理
  • 注册表形态——用 Schema Registry 统一管理,运行时自动校验
  • 文档形态——用 Markdown 或 Wiki 写给人看,配合审批流程

我个人更推荐代码 + 注册表的组合。代码形态保证版本可追溯,注册表形态保证运行时能自动拦截不兼容变更。文档形态可以作为补充,但不能作为唯一载体——人总会忘记更新文档的。

下面这张图展示了数据契约在数据管道中的位置:

数据契约在数据管道中的位置 数据生产者 数据契约 Schema Registry 数据消费者 注册 Schema 订阅 Schema 数据流 实际数据(带 Schema) 运行时校验 校验 Schema 兼容性 数据契约在生产者注册 Schema 时生效,在消费者读取数据时校验 不兼容的变更会被注册表拒绝,从源头避免生产事故

从图上你能看到:数据契约不是挂在墙上的文档,而是嵌入数据管道的一个强制校验环节。生产者注册 Schema 时,注册表会检查兼容性;消费者读取数据时,也会用契约里的 Schema 做校验。两边都对得上,数据才能流通。

核心观点:数据契约的本质是「把信任从口头承诺变成可执行的代码」。它让数据生产者和消费者之间有了一个双方都认可的、机器可读的约定。

好了,这一章的内容就这些。数据契约不是什么高深的概念,但它是整个数据治理体系的基石。后面的章节里,我们会一步步深入 Schema 演化的具体策略、兼容性检测算法、以及如何在 Kafka、Hive、Flink 等系统中落地数据契约。