在 OpenAI 扩展 Git:Pando 如何实现拍字节(Petabyte)级吞吐量
TL;DR
OpenAI 构建了 Pando,这是一个自定义的 Git 后端。它保留了标准的 Git 客户端,但通过放宽仓库范围的一致性要求并跨客户端重用 packfile,将推送延迟降低了 5 倍,并实现了每日拍字节(PB)级的数据传输。
为什么 OpenAI 需要一个新的 Git 后端
- Codex 使许多工程师能够并行工作,导致分支、推送、合并和获取(fetch)的数量呈爆炸式增长。
- 到 2023 年底,单体仓库(monorepo)面临推送缓慢、合并失败以及可靠性低于 90% 的问题。
- 现有的扩展方法(三阶段提交或共享预写日志)仍然需要全局协调或单一清单,这为并发写入或读取造成了瓶颈。
- OpenAI 希望保留与 Git 兼容的工作流,以便改进成果能惠及更广泛的社区。
“我们找到了一种方法,既能保留熟悉的工作流,又能重构后端以并行处理对不同分支的推送,并同时为许多读取者提供相同的历史记录。” – OpenAI 博客
Pando 的核心设计目标
- 水平可扩展的写入 – 允许在没有全局锁的情况下同时更新多个分支。
- 最大化读取吞吐量 – 向许多客户端提供相同的 packfile,从而充分利用网络带宽。
- Git 协议兼容性 – 无需更改现有的客户端工具。
架构突破
1. 因果一致性而非全局一致性
- 每次分支更新都会创建一个不可变的 ref version,指向已上传的 packfile 及其依赖项。
- 写入操作在每个引用(ref)上是可序列化的;只有对同一分支的推送才会发生冲突。
- 读取者看到的是一个 因果一致 的视图:不同的分支可能反映不同的时间点,这符合开发者的实际使用场景,即开发者关心的是对单个引用的更新顺序,而不是全局快照。
2. 跨客户端的 Packfile 重用
- 推送作为不可变对象存储在可扩展的对象存储中。
- 获取(fetch)操作将客户端的
have/want集合映射到已经包含所需对象的存储 packfile 中。 - Git 协议的
packfile-uri扩展允许服务器返回指向多个预先存在的包的 URL,从而避免了即时生成包。 - 结果:读取端的 CPU 和 I/O 大幅减少;单个包可以满足数千次获取请求。
3. 分层压缩 (L0-L4)
- 每次推送都会创建一个 L0 包(最小单位)。
- 后台工作进程使用日志结构合并树(log-structured-merge-tree)风格的算法将包合并为更大的 covers (L1-L4)。
- Covers 充当获取规划的跳表(skip-list),实现了 log-Δ 元数据查找,其中 Δ 是客户端当前尖端(tip)与目标尖端之间的距离。
- 压缩提高了压缩比,并减少了客户端必须下载的包 URI 数量。
与传统方法的比较
| 方法 | 写入瓶颈 | 读取瓶颈 | 一致性模型 |
|---|---|---|---|
| 三阶段提交 (3PC) | 跨副本的全局仲裁;对无关分支的推送会序列化。 | 读取速度快(本地副本),但在高写入负载下副本磁盘会饱和。 | 强一致性,所有引用的时间点快照。 |
| 预写日志 (WAL) | 单一清单更新;比较并交换(compare-and-swap)延迟限制了推送速率。 | 服务器必须从 blob 存储中读取并索引包,影响获取延迟。 | 所有引用更新的强顺序。 |
| Pando | 基于引用的原子比较并交换;仅争用引用指针。 | Packfile 重用和缓存本地交付即使在拍字节规模下也能保持较低的获取延迟。 | 因果一致性 – 每个引用可序列化,无全局快照。 |
在 1,000 个并发写入者的模拟中,Pando 保持了较低的推送至获取延迟,而 3PC 出现了写入停顿,WAL 出现了读取停顿。实际生产环境证实,在数千次并发推送的情况下,中位延迟降低了约 80%。
Pando 中的推送流程
- 客户端创建 packfile 并运行
git push。 - Pando 在单次传递中验证 packfile 的同时将其流式传输到 blob 存储。
- 多键事务记录一个新的 ref version(元数据)并原子地更新引用指针。
- 同步元数据写入保证了 读己之所写(read-your-own-write) 的一致性;异步工作(例如调度压缩)在后台进行。
复杂度:无论推送大小如何,元数据读取/写入均为 O(1)。
Pando 中的获取流程
- 客户端发送
have和wantID。 - Pando 将这些映射到一组引用版本,并选择最小的覆盖 packfile。
- 服务器返回一个空的内联包以及指向所选包的
packfile-uri链接。 - 客户端直接从区域缓存(Express)下载包 – 缓存命中率 > 99%。
复杂度:O(log Δ) 元数据读取,其中 Δ 是客户端状态和目标之间的引用版本数量。
性能数据
- 中位推送延迟:比之前的系统低约 5 倍(降低了约 80%)。
- 每日传输数据:约 1 PB 的 Git 对象。
- 峰值吞吐量:单小时内传输超过 57 TB 的包,超过 99% 由本地磁盘缓存提供。
- 网络利用率:克隆/获取操作使通用虚拟机上的 10 Gbps 链路饱和。
部署经验
- Pando 使用 Rust 在 10 周 内构建完成,核心设计由一名工程师完成,实现过程得到了 Codex 生成代码的辅助。
- 初始部署使用了读透代理(read-through proxy)来保持旧系统同步,实现了零停机迁移。
- 内部 Git 包装器为开发者、CI 和第三方集成分阶段进行了迁移。
- Codex 驱动的自动化帮助开发者通过简单的命令迁移了他们的环境。
对 Git 的贡献
- 增加了对
packfile-uri的上游支持,并改进了并发下载处理。 - 实现了“显式 haves”,允许服务器通告一个分支尖端,该尖端与推送可能省略的历史记录分开。
- 增加了 packfile 下载的追踪和字节计数指标,有助于性能调试。
- 所有补丁均可在 OpenAI 的公共 Git 分支中找到:https://github.com/openai/git,并在 https://oai-git.openai.chatgpt.site/ 进行跟踪。
社区背景
OpenAI 的努力紧随一系列大规模 Git 工程文章之后,包括:
- Cursor 的 Git at Any Scale
- GitHub 的 Architecture Optimization 系列
- Anthropic 的 Redesigning Source Control
- East River Source Control 的 What Comes After Git
这些工作共享相同的领域——海量单体仓库、AI 生成的代码以及对高吞吐量版本控制的需求——但在实现细节上有所不同(例如,Google 风格的单体仓库服务与 Pando 的因果一致性)。
要点总结
- Pando 证明了在保持 Git 客户端不变的同时,可以彻底重新设计后端以处理拍字节级的流量。
- 因果一致性对于大多数开发者工作流来说已经足够,并且消除了对全局排序点的需求。
- Packfile 重用和分层压缩将获取操作变成了缓存命中问题,而不是 CPU 密集型的包生成任务。
- 该设计在通用硬件上实现了水平扩展,使其成为任何面临类似单体仓库增长的组织的可行蓝图。
未来计划
OpenAI 计划开源 Pando 的部分内容,探索更广泛的以代理(agent)为中心的用例,并继续向 Git 进行上游贡献,以造福整个生态系统。