3、数据契约生命周期:设计、发布、消费、监控、退役
数据契约不是写一份就完事的文档。它有自己的生命轨迹。
我见过太多团队把契约当成「上线前的一次性约定」。签完就扔进 wiki 吃灰,三个月后数据对不上,谁都不认账。说白了,契约必须像软件一样管理——有设计、有版本、有监控、有退役。
这一章,我把整个生命周期拆成五个阶段。每个阶段都有坑,也有我踩过之后的解法。
3.1 设计阶段:定结构、定约束、定语义
设计阶段决定了契约的质量上限。我个人习惯,设计时至少回答三个问题:
- 数据结构是什么? 字段名、类型、是否必填、默认值。
- 业务约束有哪些? 唯一性、取值范围、枚举列表、外键依赖。
- 语义承诺是什么? 这个字段代表什么?是下单时间还是支付时间?
我在项目中遇到过最典型的坑:字段名叫 status,生产者认为是「订单状态」,消费者认为是「支付状态」。两边都没错,但数据对不上。后来我们强制在契约里加上了 description 和 example 字段。
设计阶段的产出物,我建议包含以下内容:
| 产出物 | 说明 | 示例 |
|---|---|---|
| Schema 定义 | 字段名、类型、层级结构 | order_id: string (required) |
| 约束清单 | 唯一键、外键、取值范围 | status IN ('pending','paid','cancelled') |
| 语义字典 | 每个字段的业务含义 | create_time = 用户下单时刻 |
| SLA 草案 | 数据延迟、可用性、完整性目标 | 延迟 < 5min, 可用性 99.9% |
3.2 发布阶段:注册、版本化、通知
设计好的契约不能躺在本地。必须发布到一个中心化的契约仓库(Schema Registry)。
为什么?你想想看,如果每个团队各自维护一份契约副本,改了一个字段,其他团队根本不知道。我见过最夸张的情况——生产者和消费者各有一份 JSON,字段名都不一样,数据管道跑了半年没人发现。
发布阶段的核心动作:
- 注册: 将契约推送到 Schema Registry,生成唯一 ID。
- 版本化: 每次修改必须升版本。兼容性检查(向后兼容、向前兼容、完全兼容)由 Registry 自动执行。
- 通知: 通过 webhook 或消息队列,通知所有订阅方「契约有更新」。
BREAKING,人工审批后才能发布。
发布后的契约,应该处于以下三种状态之一:
| 状态 | 含义 | 消费者能否使用 |
|---|---|---|
DRAFT |
设计阶段,还在评审 | 否 |
ACTIVE |
已发布,可消费 | 是 |
DEPRECATED |
即将退役,建议迁移 | 是(但会告警) |
3.3 消费阶段:绑定、校验、降级
消费者拿到契约后,不是直接「拿来用」就完了。消费阶段要做三件事:
- 绑定: 消费者声明「我消费的是契约 v1.2.3」。这个绑定关系要注册回 Registry,方便后续变更影响分析。
- 校验: 每次收到数据,用契约 Schema 做实时校验。字段缺失、类型不对、枚举值越界,立刻拒绝或降级。
- 降级: 如果数据不符合契约,消费者要有兜底策略。是用默认值填充?还是跳过这条记录?还是直接报错?
我建议在消费端做两层校验:
// 第一层:Schema 校验(强校验)
if (!schemaValidator.isValid(record)) {
// 记录异常,发送告警
metricsCollector.increment("contract.violation");
// 根据策略决定是否拒绝
if (strategy == STRICT) {
throw new ContractViolationException("数据不符合契约");
}
}
// 第二层:业务规则校验(弱校验)
if (record.getAmount() < 0) {
// 记录告警,但不拒绝
logger.warn("金额为负,记录ID: {}", record.getId());
metricsCollector.increment("business.rule.warning");
}
3.4 监控阶段:SLA、指标、告警
契约发布之后,不能放任不管。监控阶段要回答三个问题:
- 生产者是否履约? 数据延迟、完整性、Schema 一致性。
- 消费者是否合规? 有没有绕过契约直接读表?有没有使用过期版本?
- 契约本身是否健康? 有没有长期未更新的契约?有没有无人消费的僵尸契约?
我常用的监控指标:
| 指标 | 计算方式 | 告警阈值 |
|---|---|---|
| Schema 合规率 | 符合契约的记录数 / 总记录数 | < 99.9% 告警 |
| 数据延迟 | 当前时间 - 数据产生时间 | > 5min 告警 |
| 契约版本覆盖率 | 使用最新版本的消费者数 / 总消费者数 | < 80% 告警 |
| 僵尸契约率 | 30 天无消费的契约数 / 总契约数 | > 20% 告警 |
3.5 退役阶段:通知、迁移、清理
契约也有退休的一天。字段废弃、表下线、系统重构,都需要走退役流程。
退役阶段最容易出问题。我见过一个团队直接删了生产者的表,下游十几个消费者同时报错,数据管道全线崩溃。
正确的退役流程:
- 标记为 DEPRECATED: 在 Registry 中将契约状态改为
DEPRECATED,保留数据,但开始告警。 - 通知所有消费者: Registry 自动查询所有绑定关系,发送迁移通知。给一个明确的截止日期(比如 30 天后)。
- 灰度下线: 先停止写入新数据,观察消费者是否还有依赖。确认无误后,再清理元数据。
- 归档: 将契约历史版本归档,保留至少 6 个月,方便回溯。
退役完成后,记得清理监控指标和告警规则。不然你会收到一堆「僵尸契约」的告警,浪费精力。
数据契约的生命周期,说白了就是「从生到死」的管理流程。每个阶段都有明确的输入、输出和检查点。设计时想清楚,发布时自动化,消费时做校验,监控时看指标,退役时走流程——做到这五点,契约才能真正保障数据质量,而不是变成另一份没人看的文档。