Cursor 27分钟讲透Git托管:代码平台的竞争正在沉入对象存储
Cursor 27分钟讲透Git托管:代码平台的竞争正在沉入对象存储
后端和平台同学必看,这篇讲的是代码代理底层真正难在哪。
昨天 Cursor 发布了 Origin——代码托管平台,产品层的动作。今天这篇 27 分钟的技术博文,作者 Vicent Martí,讲的是产品下面的地基:Git 在大规模托管场景下到底难在哪。
结论先行:代码代理平台要做好,不是「多放几台机器」。核心瓶颈落在 packfile、DAG 遍历、网络传输和对象级存储。Cursor 的解法叫 Continuity——一个以 S3 为真相源(source of truth)的 WAL(Write-Ahead Log)系统。
本文提纲
- Git 托管为什么是噩梦
- 三条路线:分布文件系统、分布 packfile、分布 Git 本身
- GitHub 走过的弯路
- Spokes:GitHub 的 13 年老兵
- Spokes 在 2026 年的两个致命缺陷
- Continuity:Cursor 的 WAL 革新
- 数据:100 副本线性扩展,300+ pushes/s
- 为什么编码平台之争正在沉入对象存储
Git 托管为什么是噩梦
Git 的设计假设是:Linus Torvalds 管理 Linux 内核。内核是一个极端去中心化的项目,有大量子系统维护者,分布式版本控制是自然选择。
20 年后,Git 成了行业标准,但分布式设计对托管场景来说更多是阻碍。普通开源项目和公司都用集中式托管——一个中心 host,所有人推和拉。
问题出在 packfile。Git 的所有内容(文件、提交、树)压缩后存在 packfile 里——一个大二进制文件,必须存在于文件系统上才能被 Git 访问。packfile 既是存储格式也是网络传输格式:你 push 或 fetch 的数据都是 packfile。
一个直觉想法是:HTTP 服务放在磁盘上的 Git 仓库前面就搞定了。确实可以跑,但天花板极低。理想情况你希望仓库存在于多台机器的多个磁盘上——并行跑 Git 操作,机器挂了仓库还在。但怎么做到?
三条路线:分布文件系统、分布 packfile、分布 Git 本身
文章把三条路线按复杂度递增排列:
路线一:分布文件系统。 把仓库放在 NFS/GFS/DRBD 上,让多台机器共享文件系统。GitHub 早期试过,全部失败——Git 的随机读模式(在 packfile 里跨 GB 数据跳来跳去)和网络文件系统天然冲突。
路线二:分布 packfile。 不动文件系统层,在应用层做复制——GitHub 的 Spokes 方案,后文详述。
路线三:分布 Git 本身。 Git 是内容寻址存储(SHA-1 为 key,对象为 value),直觉上映射到分布式 KV 存储很干净。但行不通——Git 的数据布局是有向无环图(DAG),你不知道下一个指针的值,除非先取出上一个。每次 fetch 都是一次网络往返,54 个对象就是 54 轮往返。
Google 用 JGit + 分布式哈希表试过路线三,系统跑得起来,但 git clone 性能差到放弃整个设计——因为 Git 协议要求 packfile 在网络上传输,不管你服务端怎么存。
GitHub 走过的弯路
2008 年 GitHub 成立,标语是「Git repository hosting: no longer a pain in the ass」(不开玩笑,原文如此)。
早期架构:Rails 单体 + 单台机器 + 磁盘上的仓库副本。扩展 Rails app 很简单——多部署几个实例。但 Git 仓库在磁盘上,怎么多副本?
NFS:直接丢弃。Git 对文件系统语义的假设(锁、撕裂、读、同步)在本地文件系统上表现正常,在 NFS 上慢且 bug 多。
GFS:短暂部署,放弃。
DRBD(块级复制):部署时间最长,但运维噩梦,性能不好。
根本原因:packfile 在磁盘上的布局和 DAG 图结构之间没有相关性。packfile 里的对象是随机放置的、压缩的、大部分以 delta 形式存储——读一个对象要先跳图再跳磁盘,在百 GB 数据上随机跳,网络文件系统扛不住。
GitHub 最终放弃分布文件系统,转向 RPC 系统:仓库放在专用 fileserver 上,Rails app 远程操作。解决了水平扩展,但每个仓库仍只在单台机器上——可用性没解决,忙仓库的性能也没解决。
Spokes:GitHub 的 13 年老兵
2013 年 GitHub 开发 Spokes,后来成了行业标准。大多数 Git 托管服务的架构都是 Spokes 的变体。
Spokes 的三个核心选择,事后证明都是最优的:
- 不动 Git 本身,在 packfile 层做复制
- 仓库作为普通 Git 仓库存在本地 NVMe 磁盘上(随机读模式要求本地高速存储)
- 所有副本保持强一致(Git 客户端和最终一致性天然冲突)
强一致性的实现方式是 3PC(三阶段提交)。push 时,编排器把 packfile 扇出到所有副本(不需同步),然后用 3PC 对引用事务(reference transaction)做共识——引用事务比 packfile 小得多快得多。3PC 保证要么所有节点提交,要么所有节点回滚。
13 年来 Spokes 运行良好。但 2026 年的用法变了。
Spokes 在 2026 年的两个致命缺陷
缺陷一:3PC 的水平扩展天花板。
3PC 作为共识算法,每一步的延迟被集群中最慢的服务器决定。副本越多,push 吞吐越差——尾延迟在大规模下是杀手。
2013 年,3 个副本是最优配置。2026 年,企业公司的平均仓库是巨型 monorepo,3 个副本扛不住 CI 流量。但加副本?3PC 让 push 吞吐劣化。
反过来也是问题:Agent 时代会创建海量小仓库——大多数一次性、几乎不碰。Spokes 对每个仓库仍需 3 个副本,3 个基本空闲的副本不能缩减(否则不满足强一致性,有数据丢失风险)。
3PC 的地板太高,天花板太低。
缺陷二:仓库是宠物不是牛。
磁盘上的仓库是共识的真相源,每个副本都很重要。你需要:精确知道每个仓库在哪台机器上(路由表依赖外部数据库),持续校验每个仓库的 checksum,坏了要快速检测和修复。一旦 3 份里有 2 份损坏,就没有 quorum 了,系统拒绝 push。
Continuity:Cursor 的 WAL 革新
Continuity 是 Cursor 开发的 Git 存储系统,核心设计:以 S3 为真相源的 Write-Ahead Log。
graph TB
A["Git Client Push"] --> B["WALGit Primary
receive pack"]
B --> C["Write WAL entry to S3"]
C --> D["Prepare ref txn
on local NVMe repo"]
D --> E["Update WAL index
in S3 (CAS)"]
E --> F["Acknowledge push
linearizable"]
C --> G["UDP Gossip
to replicas"]
G --> H["Replica
catch up from S3"]
H --> I["Serve reads
verified via ETag 304"]
style A fill:#FF6B6B,color:#000000
style B fill:#4ECDC4,color:#000000
style C fill:#45B7D1,color:#000000
style E fill:#45B7D1,color:#000000
style F fill:#96CEB4,color:#000000
style H fill:#FFEAA7,color:#000000
style I fill:#FFEAA7,color:#000000核心设计决策:
真相源是 S3,不是磁盘。 仓库在本地 NVMe 上是暖缓存,真相永远是 WAL。仓库丢失了?从 WAL 重新物化。路由表?不需要——用 rendezvous hashing 映射,失同步也无所谓。
没有共识协议。 不需要选主、不需要 3PC。任何服务器都能当 primary,S3 的 CAS(compare-and-swap)保证原子性。设计目标是:降级时永远正确,健康时永远快。
副本数无上限。 所有副本直接从 S3 追赶。用 UDP gossip 通知副本有新数据——UDP 不可靠没关系,读操作时用 conditional GET + ETag 验证:304 表示已最新(<10ms 的元数据操作),200 表示需要追。所有副本的所有读都是强一致的,因为都对着 S3 验证。
大 monorepo: 部署 100 个副本扛 CI 流量。 百万小仓库: 每个只 1 个副本。空闲仓库连 1 个都不需要——GC 掉,下次 fetch 时从 WAL 物化。
压缩(Compaction): 只有 primary 做,结果同时应用到磁盘和 WAL。副本不 repack——直接从 S3 下载已压缩的 packfile,用带宽换 CPU。不会再有维护操作导致 failover。
数据:100 副本线性扩展,300+ pushes/s
| 指标 | S3 Standard | S3 Express One Zone |
|---|---|---|
| Push 吞吐 | 120 pushes/s | 300+ pushes/s |
| 读扩展 | 100 副本线性 | 100 副本线性 |
| 一致性 | 全部强一致 | 全部强一致 |
| 追赶延迟 | ETag 304 <10ms | ETag 304 <10ms |
压力测试跑到 100 个副本,读吞吐线性增长,push 吞吐无回退。S3 Express One Zone 上 push 瓶颈已经是 Git 压缩本身的速度了。
为什么编码平台之争正在沉入对象存储
这篇文章的信息量远超一篇产品发布稿。它讲的是:代码平台的护城河正在从产品层沉入基础设施层。
第一,Git 托管是 AI 编程时代被忽视的瓶颈。 文章最后一段说得很直接:Agent 改变了软件的工作方式——更多代码、更多 PR、更多 CI 运行。版本控制是这一切的核心,也是最难一夜之间改变的东西。Agent 创建海量小仓库(Spokes 扛不住),monorepo 流量暴增(3PC 扛不住),Git 托管基础设施的弹性变成了 AI 编程平台的天花板。
第二,对象存储成为 Git 托管的真相源。 Azure DevOps 用 MS SQL Server 存引用,Cursor 选择 WAL + S3。区别在于:WAL 不依赖外部数据库,每个仓库的完整历史状态都在 WAL 里——可以回放、可以 rewind、可以 fast-forward。S3 的持久性(11 个 9)和可用性(CAS 原子操作)让 Git 数据的强一致性有了天然的底层保障。
第三,这是 Cursor 继 Origin 之后的第二张底牌。 Origin 是产品层(代码托管 UI、API、Agent 接口),Continuity 是基础设施层(存储引擎、复制协议、可用性保障)。两层合在一起,Cursor 不只是做一个「GitHub 替代品」,是在重写 Git 托管的地基。
第四,对比全行业。 GitHub 用 Spokes 跑了 13 年,Azure DevOps 用 blob + SQL,Google 用 JGit + DHT(已放弃)。Cursor 的 Continuity 是目前公开方案中最新的设计——WAL + S3 + 无共识 + 随意副本数。它能不能在生产环境稳定跑,还需要时间验证,但设计思路的清晰度在同类系统中无出其右。
文章作者 Vicent Martí 的前 mentor 是 Shawn Pearce——Google JGit + DHT 方案的实现者。这个传承关系本身就是一段历史:师父试过路线三失败了,徒弟在路线二的基础上重构出了新方案。
对了,顺带一提:Cursor 在 8 月 14 日被 SpaceX 收购了。所以 Origin 和 Continuity 不只是产品发布,更像是被收编前的技术底牌亮牌。
参考文档与链接
- Cursor Blog: Git at any scale - Vicent Martí,27 min read,Aug 18 2026
- Cursor Changelog: Origin Code Hosting - Aug 17 2026,Origin 产品发布
- Cursor Blog: Cursor is now a part of SpaceX - Aug 14 2026
- Spokes (GitHub) - GitHub 的 Git 复制系统,2013 年至今
- Azure DevOps - 微软的 Git 托管,blob + SQL 方案
- JGit - Java Git 实现,Google DHT 方案的基础
你用过 Origin 了吗?对比 GitHub/GitLab 体验如何?评论区聊聊。觉得有用点个赞让更多人看到。
作者: itech001 来源: 公众号:AI人工智能时代 网站: https://www.theaiera.cn/ 每日分享最前沿的AI新闻资讯和技术研究。
本文首发于 AI人工智能时代,转载请注明出处。