OpenAI Pando重写Git服务端:push延迟降80%每天交付1PB

结论先说:OpenAI 用 10 周时间重写了服务端的 Git 存储层,新系统 Pando 把中位 push 延迟降低接近 80%,每天可交付接近 1 PB 的 Git 数据,单机缓存命中超过 99%。

2026 年 11 月 2 日,OpenAI 在官方博客发布了一篇名为 Scaling Git at OpenAI 的工程长文,第一次完整公开了 Pando 的架构。事情的起点很朴素:过去一年,随着 Codex 让工程师能并行处理更多工作,OpenAI 的 monorepo 在分支数、push 频率、merge 次数、CI 里的 fetch 与 clone 数量上都暴涨。到去年年底,原有 source control 系统开始变慢,merge 失败,某些时期可靠性低于 90%。

Git 协议本身没有问题,撑不住大规模并发操作的是承载 Git 服务的架构。下面按官方披露的实现细节,把三种架构的取舍、Pando 的核心机制和它付出的代价拆开讲。

问题从哪来:Codex 放大了 monorepo 的写放大

官方把负载增长的来源列得很具体。Codex 让工程师并行完成更多工作,由此产生了更多分支和 push、更多 merge、开发环境与研究任务和 CI 中更多的 fetch 与 clone、同一工程师同时准备多个 CI 变更,以及多个 push 同时触发任务去获取同一个 commit。

这些现象叠加起来指向同一个结论:Git 存储服务的瓶颈在服务端,不在客户端。传统做法是每个仓库保留完整副本,用协调器让所有副本对 ref 更新达成一致。这个模型在中小规模下很干净,OpenAI 的规模把它推到了尽头。

值得先说清楚的是,Pando 完全兼容 Git 协议和现有 Git 客户端,工程师和智能体的分支、push、fetch、clone、merge 工作流都没变。OpenAI 还基于自己的 Git fork 向 upstream Git 持续贡献补丁,其中一部分改进已经进入主线。这条路径与 GitHub Copilot Fusion 的三档编排 指向同一个问题,当代码由多个智能体并行产出时,协作层的扩展能力比单次生成质量更早触到天花板。这决定了它是一次可被外部复用的工程实践,而非只能在 OpenAI 内部跑的定制系统。

三种架构的取舍:3PC、对象存储 WAL 与 Pando

官方在文中给出了两种传统架构的建模分析,并提供了交互式模拟器做对比。

三阶段提交(3PC)的流程是:任一服务器收到 push 后,把 packfile 复制并并行发送到所有副本,协调器等待多数副本接受 ref 更新,每个副本锁定对应 ref 并检查它是否仍指向客户端预期的旧 commit,协调器发出 pre-commit 消息,获得多数确认后通知副本执行更新。好处是完整副本可就近服务读取,客户端连到哪个副本都能拿到一致的 refs 视图。代价同样明显:ref 更新必须逐个完成,每次 push 都需要协调器与副本之间多轮网络往返,等待 quorum 把副本磁盘性能和通信延迟直接放到 push 的关键路径上。模拟结论是负载增加时 3PC 的磁盘趋于饱和,写入延迟显著更高。

对象存储 WAL 的做法是把 incoming packfile 上传到 blob storage,在本地副本准备 ref 更新,然后向共享 manifest 追加一条含 ref 更新与 packfile 位置的记录,用 compare-and-swap 原子更新 manifest。它允许多个写者并行上传 packfile,manifest 提供明确的全局更新顺序。但即便 push 的是毫不相干的分支,也必须竞争更新同一个 manifest,成功 CAS 的往返延迟限制了仓库发布新 manifest 的频率。batching 可以一次发布多个 ref,却会引入排队和更高延迟。更根本的问题是,每个副本仍需从 blob storage 读取并索引 pack 才能在本地提供读取,写入速度一旦超过副本索引速度,副本就会落后,客户端 fetch 新 commit 的时间随之增加。模拟结论是 WAL 系统读取延迟显著更高。

Pando 重新审视了传统 Git 服务的两个默认假设,然后各自做了替换。

维度 三阶段提交 对象存储 WAL Pando
ref 更新顺序 全局协调,全序 共享 manifest 全序 因果一致性,按分支独立
pack 生成方 副本本地打包 副本从 blob 读取并索引 push 时生成一次,多方复用
写入扩展方式 加副本,协调器成为瓶颈 加存储,manifest 仍竞争 加 Pando 服务、扩 metadata 与 blob
模拟表现 写入延迟显著更高 读取延迟显著更高 数千客户端并发 push 性能不受明显影响
仓库级时间点快照 提供 提供 不提供

官方特别注明,这个模拟是合成的教学模型,不是生产基准测试。在真实 monorepo 测试和模拟中,Pando 都能支持数千客户端并发 push。

核心机制一:因果一致性与 ref version

第一个被放弃的假设是仓库级全局一致快照。如果所有 ref 更新都通过同一个协调点排序,不同分支上的 push 就会互相争用,即使它们毫无关系。Pando 选择放弃这一点。

替代方案是一套基于因果一致性的写入模型。客户端 push 时,Pando 把 incoming packfile 存为 blob storage 中的不可变对象,每次分支移动就记录一个新的 ref version。一个 ref version 包含新的分支 tip、提供该 tip 的 packfile,以及该 pack 依赖的早期 ref versions。blob storage 与 metadata store 都支持水平扩展。

fetch 时的流程是:找到需要重放的 ref versions,找到对应的 packfiles,把这些 packfiles 提供给客户端,客户端据此重建创建目标 ref version 时的状态。一致性保证落在四个层面:全仓库范围的因果一致性、单个 ref 更新的可串行化、单次 push 的 read-your-own-write,以及只有同一 ref 上的并发 push 才可能产生冲突。

不提供的也很明确。Pando 不提供 Git 操作期间所有 refs 的统一时间点快照,也不提供 clone 或 fetch 内所有 ref 更新的全局顺序。官方给的例子是:完整 clone 协商期间 foo 和 bar 都可能发生更新,一个客户端可能看到 foo@1、bar@2,另一个可能看到 foo@2、bar@1。OpenAI 的判断是,用户和智能体通常依赖单个 ref 上的更新顺序,而不是所有 refs 的全局更新顺序。

元数据操作的数量被刻意压平。Push 路径需要 O(1) 次 metadata 读和写,无论 push 的体积多大,所需元数据操作数保持常数级。Fetch planning 的复杂度是 O(log Δ),Δ 是客户端当前状态与目标状态之间的最短 ref-version 距离。

这里也有一个反直觉的取舍。传统 Git 服务会向客户端展示几乎所有 refs,因为展示越多,客户端能排除的服务器已有对象就越多,生成的 pack 也就越小。Pando 出于两个原因只 advertise 部分 refs。成本上,仓库有几百万分支时,完整 ref advertisement 本身可能超过 100 MiB。更重要的是可复用性,只允许客户端排除明确依赖的对象,服务端才能证明哪些依赖已被持有、哪些历史可以安全省略,进而在后续 fetch 中直接复用同一个 packfile。默认情况下,客户端 push 新 feature branch 时,Pando 只 advertise 一个指定的 trunk 分支。

代价写得很坦白:对同一分支连续 push 多次,或者在另一个 feature branch 上继续堆叠分支,客户端可能需要重新发送 trunk 之外的全部内容。OpenAI monorepo 的实际数据是,中位 packfile 小于 20 KiB,第 99 百分位小于 3 MiB。

核心机制二:服务端不维护本地仓库副本

第二个被放弃的假设是为每个客户端生成唯一 packfile。不同客户端持有的本地历史不同,传统服务会为每个客户端单独生成 pack 以避免发送对方已有的对象,代价是大量 CPU 消耗和磁盘 I/O,而且在高并发读取下难以扩展。

Pando 的做法是把生成环节前移到 push 时。服务端收到 push 后,在流式传输到 blob storage 的同时用单次 pass decode 验证 pack,不把 pack 解包到本地仓库,也不维护 loose 或 packed objects。fetch 时根据客户端已有历史选择已存储的 packfiles,返回这些 pack 的 URI,客户端直接下载。

结果是这个服务端主要执行三件事:协议协商、pack 选择、元数据操作。它不需要频繁执行昂贵的 unpack、repack 和本地 Git 对象库维护,因此可以运行在普通云 VM 上,不依赖高端专用硬件。这一点和行业里常见的重型自研方案形成对比,站内关于 OpenAI Habitat 500 PB 存储与 10 毫秒读取延迟 的拆解提到过类似权衡。

读取路径:packfile-uri 与区域缓存

fetch 侧依赖 Git 协议的 haves 与 wants。客户端声明自己已拥有哪些 commit、希望获得哪些 commit,Pando 把这两组输入映射到 ref versions,找到包含目标 commit 的版本及其历史 packfiles,计算出能覆盖客户端所需对象的 pack 集合,再补齐 side branch 缺失的 trunk 依赖。依赖规划是这里的关键,一个想要 side branch 的客户端,隐含地需要它依赖的 trunk 历史。

传输机制上,Pando 用上了 Git 协议里的 packfile-uri 特性。普通 HTTP clone/fetch 响应只允许发送一个 packfile,packfile-uri 允许服务器返回额外 pack 的下载地址。Pando 在 HTTP 响应里内联返回空 packfile,通过 packfile-uri 返回多个实际 packfile URI,客户端并行下载独立 packs。OpenAI 为 packfile-uri 向 upstream Git 贡献了多项改进,包括并发下载、中断传输后的清理、已完成下载被再次恢复,以及 fetch 接受已有 pack 时的额外校验。客户端侧还增加了 packfile-uri 下载 tracing 和 pack 生成字节数统计,用来区分慢 fetch 的时间花在生成 pack 还是传输 pack 上。这类可观测性的思路与 AKV 缓存工程开源 的处理方式一致,先把成本分布量出来再动结构。

分发层面用了两层缓存。Express 是 pack delivery service,缓存 blob storage 并返回 packfile URI,对 packfile 使用一致性哈希路由,缓存命中率超过 99%。另有独立的 metadata cache 服务缓存 metadata store。区域集群在完全命中本地缓存时可以处理 commit ID 查询和特定 ref 读。

最终的网络数字是:配合 packfile-uri、区域本地缓存和标准云厂商 VM,clone 与 fetch 可以跑满 10 Gbps 的客户端到 Pando 网络链路。部署后的整体成绩是中位 push 延迟降低接近 80%,每天交付接近 1 PB 的 Git 数据,单小时曾服务超过 57 TB 的 Git packs,其中超过 99% 的字节来自本地磁盘缓存,且只需少量 CPU 核心。合并可靠性同时获得提升。

分层 Compaction:L0 到 L4 的 pack 覆盖层

如果每次 push 都保留为一个独立 pack,客户端落后较多时可能需要下载数万个小包。在快速变化的 monorepo 里,这会显著增加文件数量、请求数量、协商开销和首字节延迟。

Pando 的做法是建立分层结构。每次 push 产生一个 L0 packfile,代表可传输的最小数据单元。后台 worker 把多个 L0 pack 聚合为覆盖连续 ref versions 的更高层 cover,形成 L0 到 L4 的层级。OpenAI 当前 monorepo 最多用到 L4。

compaction 承担两个作用。覆盖足够满时,worker 重新组织 packfile 内部对象生成单一 packfile,提升对象压缩率。没有重新打包的 cover 则作为 ref versions 之上的 skip list,扫描各层索引时跳过大量中间版本,以对数时间选出所需 packs。cover 因此分为 repacked cover 与 unrepacked cover 两种,分别对应压缩与规划性能。

有一处与多数 Git 服务不同。Pando 保留所有层级的 packs,不依靠垃圾回收删除旧 pack,而是根据客户端的 haves 和 wants 持续使用各层 pack。对通过 Pando API 读取任意对象的客户端来说,从 L0 读取通常比从 L4 读取需要更少数据,原因是小 pack 中的对象通常压缩得更少。

生产指标 数值
切换到 Pando 后中位 push 延迟 降低接近 80%(约 5 倍改善)
每日 Git 数据交付能力 接近 1 PB
单小时 Git pack 交付量 超过 57 TB
本地磁盘缓存命中字节比例 超过 99%
Express 缓存命中率 超过 99%
clone 与 fetch 可跑满带宽 10 Gbps
OpenAI monorepo 中位 packfile 小于 20 KiB
OpenAI monorepo packfile 第 99 百分位 小于 3 MiB
从启动到生产的开发周期 约 10 周

用 Codex 造 Codex:Lean 与 TLA+ 的形式化验证

开发方式本身就是这套系统的一部分。Pando 使用 Codex 开发,从启动到生产只用了 10 周。职责分工是一名工程师设计核心架构,多个 agent 团队负责实现,少数工程师负责部署。技术选型是 Rust,作为全新项目不依赖历史遗留依赖。

验证手段分四层。一层是 Git 行为一致性测试套件,让 agent 能自动验证改动是否符合标准 Git 行为。一层是确定性模拟测试工具,用于检查系统不变量、验证系统属性、找出并修复协商中的微妙 race condition、防止 pack 规划回归。第三层最特别,OpenAI 用 GPT-6 Astra 让 agent 编写 Lean 和 TLA+ 代码,建立了一套 Pando 理论,对系统属性做形式化证明,并借此发现和修复实现缺陷。第四层是持续运行,多个 agent 连续运行数百小时寻找边缘情况,配合具备 Daybreak 能力的模型全天候 red-team Git 和 Pando。

Anthropic 用 Claude 自建代码系统取代 Git 走的是另一条路线,两者的共同点在于都要把版本控制从瓶颈变成可扩展的基础设施。迁移过程采用无停机方案。Pando 最初以 read-through 与 write-through proxy 的形式部署在旧系统之前,与旧 source control 系统保持同步,逐步把流量迁移过去,全程不停机。代理层还能去重重复请求、合并请求,在转发给旧后端前降低负载。随着更多工作负载迁移到 Pando,push 逐渐填充 Pando 缓存,旧后端因缓存命中而改善可靠性。客户端侧则通过内部 Git CLI wrapper 分阶段迁移到公开 Git 构建,覆盖开发者机器和 ChatGPT 桌面应用,同时为变更请求、代码评审和自动化 API 建设专门工具,Codex 也直接参与迁移准备工作。

常见问题

Pando 和 GitHub 托管的代码托管服务是同一类东西吗?

不是同一个层级。GitHub 这类服务是完整的代码托管平台,包含仓库管理、评审、CI 等功能。Pando 解决的是其中最底层的存储与分发问题,即在一个超大 monorepo 上如何高并发地写入和读取 Git 对象。OpenAI 保留既有的托管与协作工具,只替换了最下面的存储服务层。

放弃仓库级全局快照会带来什么实际影响?

在一次 clone 或 fetch 的协商期间,不同 refs 可能处于不同的逻辑时间点,两个客户端可能看到不同的 refs 组合。对依赖单个分支更新顺序的工作流没有影响,但如果业务逻辑要求所有分支严格对齐,就需要额外的协调层。OpenAI 的判断是用户和智能体通常不依赖这种全局顺序。

只 advertise trunk 会不会让 push 体积变大?

会,但幅度可控。客户端能排除的对象变少,pack 就更大,OpenAI monorepo 的中位 packfile 是小于 20 KiB,第 99 百分位小于 3 MiB。连续向同一分支 push 或堆叠分支的场景下,客户端可能需要重发 trunk 之外的内容,这是官方明确承认的代价。收益是服务端能够证明依赖关系,从而让同一个 packfile 被多个客户端直接复用。

相关阅读

小结

Pando 的价值在于把一组被默认接受的假设逐个拆掉,仓库级全局快照、每客户端唯一 packfile、全局有序的 ref 更新,然后用手感更好的机制替换。代价写得很清楚,放弃时间点快照、同一 ref 仍有写冲突、依赖证明更复杂,这三点都摆在台面上。10 周从零到生产、80% 的 push 延迟降幅、每天 1 PB 的交付量,这些数字最终来自一次架构判断而非一次硬件升级。