外观
数据契约(Producer / Consumer)
难度与前置
难度:进阶
前置:有对外或跨团队消费的主题表/指标;知道「改列名/改粒度」会炸下游。
读完能做什么:为一张表或一条指标写出可双签的数据契约(字段/粒度/时效/空值/兼容策略/破坏性变更流程),并用签字率与违约事故数验收。
适用场景
- 跨团队共享 DWD/DWS/ADS,生产方与消费方对「什么时候算就绪、空值什么意思」理解不一致
- 指标口径变更、埋点字段增减,需要先签契约再动生产
- 对账/空跑/静默失败事后扯皮,缺一纸约定
- 要把 Schema 兼容门禁 的「能不能合」落到「合了之后谁负责」
不适用:
- OpenAPI / Protobuf / Avro 营销对比(本文是仓表与指标契约)
- Kafka 消息 Schema 演进专论(见 消息 Schema 演进;边界写在 schema-compat-gate)
- 影响面枚举步骤本身(见 lineage-impact)
- 埋点立项长流程全文(见 埋点与口径变更)
真实场景(一条)
短剧投放组把 dws_ad_roi_1d 的「消耗」从「账面消耗」改成「结算消耗」,未通知看板与对账任务。当日:
- ADS 看板 ROI 骤升 12%,业务以为投放变好
- 对账按旧口径 diff 爆表,值班按 recon-triage 才分流出「口径」枝
- 事后:生产方认为「加了注释就算通知」,消费方从未签字
按本契约重来:字段/粒度/时效/空值/兼容策略写入契约卡 → 破坏性变更走双签 + 观察窗 → 30 天内契约违约导致的对外误读 0,跨团队口径事故从每月 ≥1 降到 0。
怎么做(步骤清单)
1. 契约覆盖六块(缺一块不算签完)
| 块 | Producer 必须写清 | Consumer 必须确认 |
|---|---|---|
| 字段 | 名、类型、含义、主键/唯一键 | 依赖哪些列;禁止隐式依赖未声明列 |
| 粒度 | 一行代表什么(如 活动×渠道×业务日) | Join/聚合是否按此粒度;禁止自行「再拆一天」 |
| 时效 | 就绪定义(分区封闭时刻 / SLA) | 最早可读时刻;超时是否可降级 |
| 空值 | NULL / 默认值 / 未知桶语义 | 空值是否参与求和、分母是否剔除 |
| 兼容策略 | 仅加列?改类型?删列? | 能接受的兼容级别;破坏性变更提前量 |
| 破坏性变更 | 流程、双签、回滚、公告 | 切换日、双读窗口、停旧条件 |
口诀:契约管「约定」,门禁管「拦得住」,影响评估管「波及谁」——三件不要合成一篇空话。
2. 双签模板(可复制)
text
数据契约卡(表 / 指标)
对象:库.表 或 指标ID ________ 版本:v____ 生效日(上海):________
Producer(主题 owner):________ Consumer(代表下游):________
【字段】主键/唯一键:________
关键度量列(名/类型/单位):________
禁止隐式依赖列:________
【粒度】一行 = ________
分区键:________ 业务日切规则:________
【时效】就绪定义:________ SLA:________(链 freshness-sla)
延迟时 Consumer 行为:□等待 □读昨日 □标不可信
【空值】NULL 含义:________ 默认值:________ 未知桶:________
(对齐 null-default-semantics)
【兼容】允许:□加可空列 □加枚举值(需公告)
禁止未走变更:□改类型 □改粒度 □删/改名列 □改过滤改变行集合
兼容级别承诺:向后 / 向前 / 全兼容(与 schema-compat-gate 一致)
【破坏性变更】提前量:≥____ 工作日
必附:lineage-impact 单号 ____;双读/观察窗 ____;回滚点 ____
双签:Producer ____ Consumer ____ 日期 ____一张表多个消费者时:契约以 Producer + 代表 Consumer(通常 ADS/核心看板 owner) 为必签;其余消费者订阅变更公告即可,但破坏性变更仍须 lineage 全量点名。
3. 与指标、埋点、发布的咬合
text
推荐顺序
1) 指标/字段立项:metric-consistency / tracking-metric-change
2) 写契约卡并双签(本篇)
3) CI/测试环境跑 schema-compat-gate
4) 常规变更窗合入(change-window);破坏性另附 lineage-impact
5) ADS 出数验收后再切读(ads-publish)
6) 差异告警先走 recon-triage,不可直接改契约「抹平」4. 违约与升级
| 现象 | 算不算违约 | 动作 |
|---|---|---|
| 未签契约就改度量口径并切 ADS | 是 | 回滚或标不可信;补签;复盘 |
| 仅加可空列且兼容门禁 PASS | 否(若契约允许) | 公告即可 |
| Consumer 依赖未声明列 | Consumer 责任 | 补进契约或改下游 |
| 时效承诺连续突破无公告 | 是 | 调 SLA 或加容量;写入闭环 |
常见坑(至少这些)
只有表结构截图,没有粒度与时效
下游按错 grain Join 膨胀。把契约写成 OpenAPI 赞美诗,六块字段全空
Producer 单方「发布」即生效,Consumer 从未签字
空值语义口头约定,求和把 NULL 当 0
对照 null-default-semantics。破坏性变更只改注释不走 lineage
兼容策略写「尽量兼容」,门禁无法自动化
必须落到向后/向前/禁止项。对账失败先改契约数字「对齐业务感受」
应先 recon-triage。多 Consumer 无代表签署人,出事全员甩锅
如何验收(带数字的前后对比)
| 项 | 改前(示例) | 改后(目标) |
|---|---|---|
| 核心对外表/指标有双签契约 | <30% | 100%(P0/P1) |
| 破坏性变更含契约版本 + lineage | 罕见 | 100% |
| 因未约定口径/空值导致的对外误读 | ≥1 / 月 | 0(观察 30 天) |
| 契约六块缺项合入 | 常见 | 门禁拒绝;缺项 = 0 |
| Consumer 抽检知就绪定义 | 口头 | 抽检通过率 100% |
text
数据契约验收记录(可复制)
范围:P0/P1 对象清单 ____ 张/条
已双签:____% 六块完整:____%
观察期:____ 天 违约对外误读:____(期望 0)
破坏性变更单数:____ 含契约版本+lineage:____%
联动:schema-compat-gate / ads-publish / recon-triage 抽检 Y/N
签字(数据负责人):________ 日期:________Checklist:
- [ ] 六块齐全的双签模板可执行
- [ ] 与 metric-consistency / lineage-impact / ads-publish / tracking-metric-change / schema-compat-gate / recon-triage 边界写清
- [ ] 验收含签字率与违约事故数字
- [ ] 非 OpenAPI 教程体;无假外链;无未公开公司指标名
相关专篇(互链,不重写)
| 你要做的事 | 看哪篇 |
|---|---|
| 指标口径立项与变更 | 指标口径一致性 |
| 改表影响面 | 改表前影响评估 |
| 对外切流前验收 | ADS 出数验收 |
| 埋点/口径变更流程 | 埋点与口径变更 |
| 合入前兼容检查 | Schema 兼容门禁 |
| 对账差异分流 | 对账失败分诊 |
| 本篇 | 只定 Producer/Consumer 约定与双签,不替代上述专篇 |
相关面试题
题库小程序链接待定;先用站内锚点占位。
- [ ] 题:数据契约最少要覆盖哪六块?缺「粒度/时效」为何不能算签完?(考察点:六块完整性 + 签字率 100%)→ 占位:
#todo-interview-data-contract-six - [ ] 题:破坏性变更在契约里如何与 lineage-impact、变更窗咬合?(考察点:提前量/双签/回滚)→ 占位:
#todo-interview-data-contract-breaking - [ ] 题:Consumer 依赖未声明列算谁违约?如何验收整改?(考察点:隐式依赖边界)→ 占位:
#todo-interview-data-contract-implicit - [ ] 题:契约与 schema-compat-gate、OpenAPI 文档各管什么?(考察点:边界/不适用)→ 占位:
#todo-interview-data-contract-boundary