每秒超过300次Push。这是Cursor在合成测试中跑出的数字,用的是S3 Express One Zone。同一套系统换成S3 Standard,这个数字掉到120次。差距来自存储层,不是代码层。

Cursor给这套Git存储架构起了个名字:Continuity。它的核心思路只有一句话——把S3上的预写日志(Write-Ahead Log,WAL)当作数据的最终依据,不再靠副本之间的协调来保证一致性。

打开网易新闻 查看精彩图片

副本越多,协调越贵

要理解Continuity在改什么,得先看传统方案怎么做。GitHub的Spokes架构维护多个NVMe副本提供存储能力,用三阶段提交更新Git引用。副本之间保持同步,读取请求可以交给任意一个副本处理。

问题出在扩展性上。副本越多,协调操作带来的开销就越大。这套逻辑在副本数量可控时运转良好,但副本规模一旦上去,同步成本会吃掉大部分收益。

Continuity换了一条路。Push上传的数据写入S3,相应的引用更新记录到WAL中。只有所需数据完成持久化,系统才会确认Push成功。这意味着请求得到确认时,数据已经可靠存储。

Cursor工程师Vicent Martí的说法是,本地NVMe上的Git仓库只是温缓存,并非权威副本。系统通过Rendezvous Hashing(会合哈希)选择优先处理请求的节点,同时利用S3上的原子比较并交换(Compare-and-Swap)操作,让任意服务器都能接受Push请求。如果本地没有相应的仓库副本,系统也可以根据WAL重新生成仓库。

Gossip丢了也不影响正确性

WAL更新通过UDP Gossip协议在节点间传播,系统通过带条件的S3读取来校验副本状态。Cursor称这类读取的平均耗时不到10毫秒。

打开网易新闻 查看精彩图片

关键在于,即使Gossip消息丢失,也不会影响数据正确性,因为S3始终是事实来源。传播机制只负责加速收敛,不负责保证正确。这个分工把一致性保障的核心从副本层转移到了持久化对象存储。

在合成测试中,Cursor在最多使用100个副本时,读取能力能够随副本数量线性增长。单体仓库可以为CI工作负载扩展到数百个副本;对于暂时没有活动的仓库,则可以等到需要时再生成本地副本。

Git压缩的处理方式也变了。压缩只由主副本执行,其他副本直接从S3下载压缩后生成的packfile。这样做减少了重复的CPU开销,但会增加带宽消耗。当吞吐量进一步提高时,Git压缩成为新的性能瓶颈。

把Git存储当数据库设计

这套设计引发了与数据库架构的比较。高级软件工程师Maksim Al Dandan在相关讨论中指出,Continuity相当于把Git存储当作数据库来设计。在这一思路下,Push的一致性保证、Force Push涉及的事务,以及时间点恢复(Point-in-Time Recovery)等问题,都值得进一步关注。

Casey Lee是Liatrio的CTO,曾在AWS工作。他在相关评论中强调了这一架构转变:S3中的WAL才是事实来源,本地NVMe只负责缓存。Lee同时指出,Cursor公布的性能数据尚未经过独立验证。

Cursor表示,测试中的Push操作满足线性一致性要求,且数据在请求得到确认前就已持久化到外部存储;Clone操作也始终保持一致性。这套架构既能应对CI负载繁重的大型代码仓库,也能支持Coding Agent创建的大量小型仓库。

代价是明确的:系统需要依靠存储校验和异步传播来保证副本状态,并付出额外的带宽成本,以减少副本之间的协调开销。用带宽换协调,用对象存储换副本同步——这笔账在Git托管规模持续膨胀的当下,值得算一算。