Delta 协议演进治理指南:解读 protocol_rfcs 目录与 RFC 全流程
【免费下载链接】deltaAn open-source storage framework that enables building a Lakehouse architecture with compute engines including Spark, PrestoDB, Flink, Trino, and Hive and APIs项目地址: https://gitcode.com/GitHub_Trending/del/delta
Delta Lake 的事务日志协议(Transaction Log Protocol)定义了表格式(table format)的一切行为,其任何变更都关乎所有读写引擎的兼容性。为保证协议演进的严谨与透明,Delta 仓库自 2024 年起引入了一套以 RFC 为中心的治理流程,所有提案、已接受与已拒绝的 RFC 均收录在 protocol_rfcs 目录中。本文以该目录及其 README 为骨架,完整梳理 RFC 清单、三步生命周期、模板规范与状态迁移规则,并结合仓库中的 PROTOCOL.md、模板文件及代表性 RFC 文档进行源码级佐证,帮助读者理解 Delta 协议变更从提案到规范落地的全过程。
protocol_rfcs 目录:协议演进的"档案室"
打开仓库根目录下的protocol_rfcs目录,其结构本身就是协议治理的缩影:
- accepted/:已被接受并合入 Delta 规范的 RFC(如 Catalog-Managed Tables、In-Commit Timestamps、Type Widening、Variant 等);
- rejected/:被拒绝的 RFC(如 Managed Commits);
- template.md:新建 RFC 必须克隆的模板;
- 目录根部存放仍在评审中的 Proposed RFC(如 checkpoint-protection.md、iceberg-compat-v3.md、interval-types.md 等)。
这些 RFC 文档与仓库根部的 PROTOCOL.md(Delta 事务日志协议正式规范,全文 3000+ 行)形成分工:RFC 是"提案与讨论记录",PROTOCOL.md 是"最终生效规范"。一个 RFC 被接受后,其内容会折叠(fold)进 PROTOCOL.md 对应章节。例如 accepted/variant-type.md 开头便注明 "Folded into PROTOCOL.md",而 PROTOCOL.md 中确实存在完整的 Variant Data Type 章节;accepted/in-commit-timestamps.md 提出的inCommitTimestamp字段也已落地为规范中commitInfo的可选字段(见 PROTOCOL.md)。
RFC 全量清单
截至本仓库快照,protocol_rfcs/README.md记录了自 2024 年 2 月 6 日该流程引入以来全部提案、接受与拒绝的 RFC。以下三张表继承自原文档,并将其中外部链接统一替换为仓库内相对路径。
进行中的 Proposed RFCs
| 提案日期 | RFC 文件 | 关联 issue | RFC 标题 |
|---|---|---|---|
| 2023-02-26 | column-mapping-usage-tracking.md | #2682 | Column Mapping Usage Tracking |
| 2024-04-30 | collated-string-type.md | #2894 | Collated String Type |
| 2025-03-13 | checkpoint-protection.md | #4152 | Checkpoint Protection |
| 2025-03-18 | iceberg-writer-compat-v1.md | #4284 | IcebergWriterCompatV1 |
| 2025-05-19 | iceberg-compat-v3.md | #4574 | IcebergCompatV3 |
| 2025-11-20 | materialize-partition-columns.md | #5555 | Materialize Partition Columns |
| 2026-02-19 | nanosecond-timestamps.md | #6081 | Nanosecond Timestamp Primitive Types |
| 2026-04-22 | iceberg-v4-metadata.md | #6640 | Iceberg V4 Adaptive Metadata Tree |
| 2026-06-23 | interval-types.md | #7077 | Interval Types |
已接受的 Accepted RFCs
| 提案日期 | 接受日期 | RFC 文件 | 关联 issue | RFC 标题 | |:-|:-|:-|:-|:-| | 2025-04-07 | 2026-02-17 | accepted/catalog-managed.md | #4381 | Catalog-Managed Tables | | 2023-02-28 | 2023-03-26 | accepted/vacuum-protocol-check.md | #2630 | Enforce Vacuum Protocol Check | | 2023-02-02 | 2023-07-24 | accepted/in-commit-timestamps.md | #2532 | In-Commit Timestamps | | 2023-02-09 | 2025-01-28 | accepted/type-widening.md | #2623 | Type Widening | | 2023-04-24 | 2025-02-14 | accepted/variant-type.md | #2864 | Variant Data Type | | 2025-05-06 | 2026-05-01 | accepted/variant-shredding.md | #4032 | Variant Shredding |
已拒绝的 Rejected RFCs
| 提案日期 | 拒绝日期 | RFC 文件 | 关联 issue | RFC 标题 |
|---|---|---|---|---|
| 2023-02-14 | 2025-04-07 | rejected/managed-commits.md | #2598 | Managed Commits |
值得注意的是,Accepted 列表中最新的 catalog-managed.md 与 Rejected 列表中的 managed-commits.md 主题相近(都是让外部实体接管提交原子性),但前者从"目录(Catalog)作为提交事实来源"切入,最终被接受;后者则被拒绝。这组对照恰好说明:协议变更的成败往往取决于提案对生态各方约束的设计是否周全。
RFC 生命周期:三步走流程
protocol_rfcs/README.md将一次协议变更的全过程归纳为三个阶段,本文结合仓库中的模板与具体 RFC 文档逐层展开。
第一步:提交初始提案(Make initial proposal)
任何协议变更的起点都是在 GitHub 上创建一个Protocol Change Request类型的 issue,该 issue 将作为该协议变更所有讨论的中心场所。提案者可以在 issue 描述中附带设计文档链接;如果提案带有原型或其他可行性验证(pathfinding),相关代码改动应当放在一个公开的 PR 中,便于社区评审。
第二步:添加 RFC 文档(Add the RFC doc)
issue 建立并与社区讨论、就"该特性应当实现"达成基本共识后,在合入任何 master 代码之前,必须先通过 PR 提交 RFC 文档。具体要求:
- 克隆模板:复制 template.md 并创建新的 RFC Markdown 文档;
- 交叉引用 issue:RFC 中必须用 "see #xxx" 关联 issue。严禁使用 "closes #xxx"、"fixes #xxx"、"resolves #xxx" 等措辞——因为不希望 RFC PR 合并时自动关闭 issue(issue 要等到特性最终被接受或拒绝时才关闭)。
模板本身结构极简却信息完整:template.md 要求 RFC 标题使用"表特性名称/有意义的名字",正文首行标注关联 issue,随后给出协议变更的总体描述(general description / context),并预留"对 PROTOCOL.md 的修改"区块。这种"标题—issue 链接—背景—规范修改草案"的四段式结构,保证每个 RFC 都具备可评审、可追溯的最小信息集。
README 还给出了两条对贡献者至关重要的工程约束:
- 临时特性名约定:对于表特性(table feature),强烈建议任何实验性支持使用带
-dev后缀的临时特性名。这向潜在用户明确传达"该实验特性不提供未来兼容性保证"; - 代码隔离:与提案特性相关的代码在 RFC 达到 "proposed" 状态(即 RFC PR 经过公开评审并合并)之前不得合入主分支;在 RFC 被接受(即变更合入 Delta 规范)之前,相关代码必须用特性开关(feature flags)与生产代码隔离,确保不影响现有用户。
第三步:接受或拒绝 RFC(Accept or reject the RFC)
RFC 从 "proposed" 走向最终定论,需要满足两条硬性验收标准:
- 存在一个经过充分测试的生产实现(例如在 delta-spark 中);
- 至少有一些讨论和/或原型(优先)证明该特性在 Delta Kernel 中的可行性。
满足标准后,通过 PR 完成"协议定稿"动作:
- 密切验证协议规范改动与实际生产实现的一致性;
- 用 "closes #xxx" 交叉关联 PR 与原始 issue(此时才允许关闭 issue),并将 issue 标题更新为
[ACCEPTED]前缀,使提案结果一目了然; - 更新 PROTOCOL.md 正式规范;
- 将 RFC 文档移入
accepted子目录,并更新状态索引; - 从所有代码中移除表特性名里的
-dev等临时/预览后缀。
若 RFC 被拒绝,则对应的 PR 需要:以 "closes #xxx" 关闭 issue 并将标题改为[REJECTED]、将 RFC 移入rejected子目录、更新状态索引、删除与该特性相关的所有实验/预览代码。rejected/managed-commits.md 就是这条路径的完整实证。
从提案到规范:代表性 RFC 的源码级印证
协议的每一步演进,最终都沉淀为 PROTOCOL.md 的具体条款与仓库源码中的实际行为。以下选取几个有代表性的 RFC,对照其文档与规范现状进行解读。
Catalog-Managed Tables:目录成为提交的事实来源
accepted/catalog-managed.md 提出新的读写表特性catalogManaged,它改变了 Delta 发现与访问表的方式:传统 Delta 协议完全依赖文件系统完成读时发现(read-time discovery)与写时提交原子性(通过 PUT-if-absent),而该特性让管理表的 Catalog 成为"某次提交尝试是否成功"的事实来源。文档列举了六大收益,从拒绝绕过 Catalog 的文件系统提交、支撑跨表事务,到由 Catalog 直接托管小提交内容、发放存储凭证、充当最新表版本权威来源(不再需要 LIST_delta_log),乃至基于提交触发 VACUUM、布局优化、UniForm 转换等后续动作。
该 RFC 对规范的多处修订同样值得关注:提交文件可能暂存在_delta_log/_staged_commits目录,命名遵循<version>.<uuid>.json(version 为 20 位零填充的提议提交版本号);commitInfo动作必须携带唯一事务标识txnId;元数据清理(Metadata Cleanup)时还需删除_staged_commits中早于 cutoff 检查点的 staged 提交文件。这些细节共同勾勒出"Catalog 裁决、文件系统暂存、定时回填"的混合提交模型。
In-Commit Timestamps:让时间旅行不再依赖文件修改时间
accepted/in-commit-timestamps.md 解决的是一个隐蔽但关键的可靠性问题:TIMESTAMP AS OF 时间旅行此前依赖提交文件的文件系统修改时间,一旦文件操作改变 mtime,时间旅行结果就可能出错。该 Writer 特性要求每次提交的commitInfo动作(且必须是提交中的第一个动作)包含inCommitTimestamp字段,取"写入方尝试提交的时刻"与"上一个提交的inCommitTimestamp+ 1 毫秒"两者中的较大值,从而保证跨提交严格单调递增。
对于特性启用前已有的历史提交,规范用两个表属性delta.inCommitTimestampEnablementVersion与delta.inCommitTimestampEnablementTimestamp记录启用边界,读者据此判断每个版本应使用inCommitTimestamp还是文件修改时间。这些条款均已合入 PROTOCOL.md(对应commitInfo的inCommitTimestampOpt可选字段与读者/写者要求段落)。
Type Widening 与 Variant:类型系统的两次扩展
accepted/type-widening.md 定义了一组明确的"加宽"转换规则:整数加宽Byte -> Short -> Int -> Long、浮点加宽Float -> Double、日期加宽Date -> Timestamp without timezone,以及带精度/标度约束的 Decimal 加宽(Decimal(p, s) -> Decimal(p + k1, s + k2),要求k1 >= k2 >= 0)。类型变更历史以delta.typeChanges键记录在最近祖先 StructField 的 metadata 中,对 map key/value 或 array element 的变更通过fieldPath("key"/"value"/"element",嵌套时以点号分隔前缀)定位。
accepted/variant-type.md 则为半结构化数据引入variant类型:在 Parquet 中表示为包含value与metadata两个 binary 字段的 struct,并给出了 JSON 编码的 Schema 示例。文档还以表格形式明确了该类型与分区列、聚簇列、列统计、生成列、CHECK 约束、默认值、Change Data Feed 等既有特性的兼容矩阵(例如 Variant 不可作为分区/聚簇列,不支持 min/max 统计,仅支持 nullCount)。这两个特性在 PROTOCOL.md 中均有对应章节,读者可在 PROTOCOL.md 中查阅完整规范。
Checkpoint Protection:为安全移除特性铺路
checkpoint-protection.md 仍是 Proposed 状态,但它解释了 Delta 协议治理中一个少为人知的问题:移除表特性(DROP FEATURE)通常需要截断表历史,而协议要求随版本单调递增,导致移除特性前必须等待 24 小时避免损坏表。checkpointProtection通过"受保护检查点"在特性移除边界充当屏障,把旧读者不支持的提交记录"隐藏"在屏障之后,从而允许单次执行 DROP FEATURE 完成特性移除。该特性要求写者在delta.requireCheckpointProtectionBeforeVersion指定版本之前不得清理/新建检查点,除非确认支持该版本的表协议;在历史清理时,写者必须先删提交、后删检查点,且要么完整支持被清理版本、要么一次性截断到边界版本。它同样适用于协议不再单调递增后,防止写者为不支持的旧版本写出损坏的检查点。
Managed Commits:一条被拒绝的路径
rejected/managed-commits.md 曾提议引入managedCommit表特性,让外部提交所有者(commit-owner)而非文件系统提供提交原子性,并定义了_delta_log/_commits暂存目录、提交回填(backfill)与维护操作约束。虽然该提案最终被拒绝(提案日期 2023-02-14,拒绝日期 2025-04-07),但它与后来被接受的 catalog-managed 思路一脉相承,且其文档中对"谁拥有提交、如何保证原子性"的讨论至今仍是理解 Delta 提交协议的重要背景。
如何参与协议演进
对于想为 Delta 协议贡献力量或跟进其演进的开发者,仓库内提供了清晰的入口:
- 阅读正式规范 PROTOCOL.md,理解表特性(Table Features)、reader/writer 版本(Reader Version 3 / Writer Version 7)等基础概念;
- 翻阅 protocol_rfcs 目录下处于 Proposed 状态的 RFC,这些是尚未定论、最需要社区讨论的内容;
- 对照 template.md 了解新 RFC 的撰写骨架,遵循 README 中"先 issue 后 RFC、
-dev后缀、feature flag 隔离、验收后再合入规范"的节奏推进自己的提案。
协议治理的价值在于:任何引擎(Spark、Flink、Trino、PrestoDB、Hive)都能依据同一份规范实现互操作,而 RFC 机制确保了这份规范的每一次变化都有据可查、有讨论可循、有代码可验。掌握protocol_rfcs目录与这套流程,也就掌握了阅读和理解 Delta 协议演进脉络的钥匙。
【免费下载链接】deltaAn open-source storage framework that enables building a Lakehouse architecture with compute engines including Spark, PrestoDB, Flink, Trino, and Hive and APIs项目地址: https://gitcode.com/GitHub_Trending/del/delta
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考