外观
Schema 兼容门禁(仓表 / 任务侧)
难度与前置
难度:进阶
前置:表变更走 Git/作业仓库;测试环境能建表或读 schema 快照;知道下游作业会 SELECT 具名列。
读完能做什么:在合并/部署前跑通「仓表 + 下游作业」兼容门禁(向后/向前/破坏性分级),用门禁拦截率与漏网事故数验收。
适用场景
- 改 Hive/Iceberg/Spark 表结构或写入 schema,担心下游任务编译期或运行期炸
- 要把「加可空列可过、删列必须拦」写进 CI,而不是靠人眼
- 短剧投放等主题多下游(对账、ADS、训练样本)并行,需要统一门禁
- 已有 数据契约,需要可自动执行的技术闸刀
不适用:
- Kafka / 注册中心消息 Schema 演进全文(见 kafka/schema-evolution;本文只管仓表与批/流作业读表)
- 影响面人工枚举与业务签字(见 lineage-impact)
- ADS 业务验收与切流(见 ads-publish)
- 造数与脱敏样例集设计(见 test-fixture;门禁应消费样例)
真实场景(一条)
短剧投放 dwd_ad_event 有人将 cost 从 decimal(18,4) 改为 double,并删除少用列 creative_extra。CI 只跑了单测「本作业能写」。上线后:
- 下游 Spark 作业仍按 decimal 反序列化,夜间批失败
- 另一个 Hive 视图
SELECT creative_extra直接挂,看板空窗 - 消息侧 Kafka schema 并无变更,有人误去改 Registry——边界澄清:这是仓表门禁漏了
按本门禁:PR 上比对 schema diff → 分级(类型收窄/删列 = 破坏性)→ 下游作业在测试环境对新表结构旧样例 + 旧表结构新样例各跑一遍 → 破坏性无豁免单则拒绝合并。观察 30 天:兼容类生产事故 0,破坏性变更 100% 带豁免与双读计划。
怎么做(步骤清单)
1. 先定兼容级别(仓表语言)
| 级别 | 含义(读方视角) | 典型变更 | 门禁默认 |
|---|---|---|---|
| 向后兼容 | 新表可被旧读方安全读 | 加可空列、加分区(慎)、仅文档 | 可自动过 |
| 向前兼容 | 旧表可被新读方安全读 | 新读方不依赖新列;写方仍写旧列集合 | 读方 PR 可过 |
| 全兼容 | 双向 | 极少;枚举加值且双方忽略未知 | 可过 + 公告 |
| 破坏性 | 旧读或旧写必伤 | 删列、改名、改类型、改粒度、改非空约束收紧 | 拒绝,除非豁免单 |
边界一句话:消息 Schema 看 Registry;仓表 Schema 看 Metastore/表 DDL + 作业读列集合。 两边都要通过时分别挂专篇,不互相替代。
2. CI / 测试环境门禁流水线
text
schema-compat-gate(建议)
1) 解析 PR:表 DDL diff + 写入 schema(Spark StructType / ORM)
2) 对照主分支 schema 快照 → 输出变更类:additive / breaking / unknown
3) 拉取下游作业清单(来自 lineage 或仓库 CODEOWNERS 映射)
4) 对每个下游:
a. 用 test-fixture 样例在「新 schema」上跑读任务(向后)
b. 若读方也变更:用「旧 schema 快照」跑新读逻辑(向前)
5) 破坏性:检查是否附豁免(契约版本 + lineage-impact + 双读计划)
6) 无豁免 → fail;有豁免 → 人工标签 + 变更窗 L2text
门禁报告卡(可复制)
PR / 作业:________ 表:________
变更类:□additive □breaking □unknown
向后检查:PASS/FAIL 向前检查:PASS/FAIL/N/A
下游覆盖数:____ / 应覆盖 ____
豁免单号(若 breaking):________
契约版本:________ lineage:________
结论:□合并 □拒绝 □待人工3. 加性 vs 破坏性:操作清单
| 变更 | 建议 | 测试要点 |
|---|---|---|
| 加可空列 | 向后兼容;写方填 NULL 或默认 | 旧读 SELECT * 或具名列仍绿 |
| 加非空列无默认 | 破坏性 | 旧写失败;必须双写或分期 |
| 删列 / 改名 | 破坏性 | 下游具名引用必挂 |
| decimal→double 等 | 破坏性(精度/语义) | 对账与指标样例 |
| 分区键变更 | 破坏性 | 路径与恢复演练 |
| 仅注释/表属性 | 文档级 | 可过 |
短剧投放示例:给 dwd_ad_event 增加可空 settle_cost,旧看板仍读 cost → additive 可过;若直接改 cost 含义而不加列 → 破坏性,走契约 + 双列双读。
4. 与契约、样例、发布的分工
- 契约:约定允许哪些兼容级别(data-contract)
- 本门禁:自动化拦住违约变更
- test-fixture:提供回归输入
- lineage-impact:破坏性豁免的影响面人工单
- ads-publish:业务出数验收,不替代 schema 门禁
- kafka/schema-evolution:Topic 消息演进;表门禁 FAIL 时不要去改 Registry「碰运气」
常见坑(至少这些)
只测写作业,不测下游读作业
本作业绿、下游红。把 Kafka 兼容策略原样套到 Hive 表
工具链与失败模式不同。SELECT * 掩盖删列,门禁误报安全
应用具名列清单或展开视图定义。类型「能跑」当兼容(decimal→double)
口径与精度已破。破坏性靠群里说一声绕过 CI
测试环境 schema 与生产快照漂移
门禁比的是过期快照。加分区字段却当 additive,恢复与路径全炸
门禁 PASS 就切 ADS,跳过业务验收
仍要 ads-publish。
如何验收(带数字的前后对比)
| 项 | 改前(示例) | 改后(目标) |
|---|---|---|
| 表结构 PR 经兼容门禁 | <50% | 100%(主题表) |
| 破坏性无豁免合入 | ≥1 / 季 | 0 |
| 因删列/改类型导致的下游夜间红 | 有 | 观察 30 天 0 |
| 下游覆盖率(门禁实际跑到的读方) | 未知 | ≥ 契约点名下游 100% |
| 快照与生产 schema 漂移 | 常见 | 每日同步;漂移告警 0 未修 |
text
Schema 兼容门禁验收(可复制)
主题:________ 观察期:____ 天
门禁覆盖 PR 比例:____%
破坏性无豁免合入:____(期望 0)
下游漏测导致事故:____(期望 0)
抽检:additive 样例 PR ____;breaking 带豁免 ____
与 data-contract / test-fixture 联动 Y/N
签字(主题 owner):________ 日期:________Checklist:
- [ ] 向后/向前/破坏性分级表可执行
- [ ] CI 步骤含下游读任务与豁免检查
- [ ] 明确与 kafka/schema-evolution 边界
- [ ] 链到 data-contract / test-fixture / lineage-impact / ads-publish
- [ ] 验收含拦截与漏网数字;无假外链
相关专篇(互链,不重写)
| 你要做的事 | 看哪篇 |
|---|---|
| Producer/Consumer 约定 | 数据契约 |
| 回归造数 | 测试样例集 |
| 破坏性影响面 | 改表前影响评估 |
| 对外切流验收 | ADS 出数验收 |
| 消息 Schema | Kafka Schema 演进 |
| 本篇 | 只做仓表/任务侧兼容门禁,不重写消息专篇 |
相关面试题
题库小程序链接待定;先用站内锚点占位。
- [ ] 题:仓表「向后兼容」与「破坏性」如何用加列/删列/改类型举例?门禁默认策略是什么?(考察点:分级表)→ 占位:
#todo-interview-schema-compat-levels - [ ] 题:为何 CI 必须跑下游读任务而不仅是写作业?(考察点:下游覆盖率验收)→ 占位:
#todo-interview-schema-compat-downstream - [ ] 题:仓表门禁与 Kafka Schema 演进的边界如何一句话说清?(考察点:不适用/边界)→ 占位:
#todo-interview-schema-compat-vs-kafka - [ ] 题:破坏性变更要过门禁最少附哪些豁免材料?(考察点:契约+lineage+双读)→ 占位:
#todo-interview-schema-compat-waiver