Agent 把 Git 单仓库推爆了怎么扩容?OpenAI Pando 拆解:不换客户端不改工作流,推送延迟降 80%

问题的样子:不是 Git 到极限,是服务方式到极限

去年底开始,OpenAI 的 monorepo 出现了典型的「并发压垮源码服务」症状:fetch 变慢、push 排队、merge 频繁失败,可靠性一度跌破 90%。原因不是仓库变大本身,而是 Codex 改变了开发节奏——一个工程师同时挂好几个改动等 CI,一次 push 会触发多组任务去 fetch 同一批提交,分支数、push 数、merge 数、clone 数全部陡增。

他们面对一个选择题:是 Git 本身不行了,还是「怎么对外提供这个仓库」的方式不行了?结论是后者。于是有了 Pando:保留 Git 协议和客户端不变,把服务端彻底重写。上线后中位推送延迟降了近 80%,如今每天对外交付约 1PB 的 Git 数据,只需要少量 CPU 核心。

这篇文章把它讲成一个可复用的架构题:单仓库高并发读写,到底该怎么拆。

先补课:Git 传输到底在传什么

要看懂任何 Git 扩容方案,先理解仓库由两部分组成:对象(object)和引用(ref)。对象分四种:blob 存文件内容、tree 存目录结构、commit 指向一个根 tree 加若干父提交、tag 打标记。对象用内容的哈希标识、不可变——改一个文件只产生一个新 blob,没变的文件继续复用旧对象。引用(分支/标签)只是指向某个 commit 的可变指针。

fetch 的协商过程:客户端告诉服务端「我要哪些 commit、已有哪些」,服务端从目标 commit 出发沿提交图遍历,剔除客户端已有的,把剩下的打包成 packfile 发回去。push 反过来:客户端根据服务端广播的 ref 列表构造一个尽量小的 pack 上传,并请求更新对应 ref。

两个关键推论:一、复制一个 Git 仓库等于同步对象加同步引用,且副本在能提供新引用之前,必须先拿到它指向的全部对象;二、给每个客户端「量身定制」packfile 是 CPU 和磁盘 I/O 大户——这是后面所有方案的分歧点。

两条常规路线,各卡在哪

路线一:多副本 + 三阶段提交(3PC)。每台服务器存完整仓库副本,push 到达时把 packfile 并行发给所有副本,多数派确认后才发布这次 ref 更新。优点是任何副本都能本地服务读请求,客户端还能看到全仓库的一致性视图。代价是引用只能一次一个地更新、每次 push 多轮往返、等待多数派的磁盘与通信延迟直接压在推送路径上。写流量一大,副本磁盘先饱和,写延迟雪崩。

路线二:共享预写日志(WAL)。push 时把 packfile 传进对象存储,再用一次 compare-and-swap 原子更新共享 manifest,给所有 ref 更新排全序。写可以并行上传,但所有更新挤同一个 manifest,CAS 往返延迟决定了全仓库的发布频率;副本还必须先把日志里的 pack 读出并建好索引才能对外服务,写一旦超过消化速度,读延迟跟着涨。

两条路的共同病根:都默认「全仓库必须有一致的点时间视图」,于是所有写天然竞争同一个串行化点。

Pando 的两个反直觉取舍

取舍一:放弃全仓库一致性,换写并行。Pando 只保证单个 ref 上的更新可串行化,外加因果一致性。push 到达时,packfile 原样流式写入对象存储(单遍解码校验),再用一个多键事务在元数据存储里记录「ref 版本」——新 tip、供数的 pack、它依赖的历史版本,整个写路径只有 O(1) 次元数据读写。fetch 时按客户端已有历史挑选所需 pack,O(log Δ) 次元数据读。跨分支没有统一点时间视图:同时读 foo 和 bar 可能看到不同时刻的状态。但实践里用户和 Agent 依赖的从来只是单个分支的更新顺序,这个交换很划算。

取舍二:不为每个客户端定制 packfile,用复用换吞吐。服务端把推上来的 pack 原样存成不可变对象,fetch 时把同一份字节发给多个客户端——哪怕客户端会多下载几个已有对象。服务节点只做协商和选包,不解包、不重打包,可以跑在廉价机器上;配合带区域缓存的分发服务 Express,单小时已服务 57TB,其中 99% 以上字节来自本地磁盘缓存。

还有一个细节值得学:push 协商时不广播全量 ref(分支上百万时广播本身就能超过 100MiB),只广播指定的 trunk 分支作为公共基底。客户端生成的 pack 因此只依赖服务端明确允许排除的历史——这份 pack 才能被后续 fetch 原样复用,读放大被彻底压住。

验证与迁移:教科书式的渐进上线

Pando 从立项到生产只用 10 周:核心由一位工程师设计、Agent 团队实现,用 Rust 编写、零遗留依赖;用一致性测试套件对齐标准 Git 行为,用确定性仿真抓竞态和回归,甚至让 Agent 用 Lean 和 TLA+ 形式化出「Pando 理论」来证明系统性质、修实现 bug,红队 Agent 全天候对抗测试。上线方式是先做读写穿透代理:新旧系统保持同步,逐个业务切流,全程零停机。客户端侧同步发布了 OpenAI 自己的 Git 发行版——并行下载与索引 pack、explicit haves 让 --force-with-lease 在新架构下可用等改进,多项已合入上游 Git。

普通团队能带走什么

第一,遇到「工具到极限」,先分辨是协议到极限还是实现到极限——保持协议兼容的渐进替换是风险最小的路,工程师和 Agent 的工作流一行不用改。第二,「给每个请求定制最优响应」在超高并发下是反模式,可复用的粗粒度响应加缓存,比精确但昂贵的计算更能扩。第三,一致性是可以谈判的:把「全仓库点时间一致」降级成「单对象可串行化 + 因果一致」,往往就解开了一切串行化的死结。Agent 时代仓库并发只会更凶,这三条判断比任何具体技术都耐用。

Logo

更多推荐