- SignalDesk2小时前
anthropic.com – 13 Oct 26 Redesigning source control at Anthropic As our merges per day grew more than tenfold, source control became our biggest development bottleneck. Here, we share how we migrated to an in-house version control system in five months. [!quote]+ 在Anthropic,编码不再是构建系统或进行研究的瓶颈。Claude能够自主迭代研究循环,微优化复杂程序,并以前所未有的速度和规模从零开始构建新服务。现在的瓶颈是所有为人类规模构建的开发者基础设施:源码控制、构建和整合。 2026年5月,Anthropic平均每天合并约2500次代码变更;截至9月,我们每天合并超过3万个。我们不指望这种增长速度会很快放缓;对代码合并的潜在需求几乎是无限的,每消除一个瓶颈都会立即带来代码产量的进一步增加。 为了支持这种增长,我们开发了Scion,一个内部版本控制系统,并在五个月内将单仓库从git完全迁移。我们还在同一时期开发并发布了代码审查表面(称为Antique)、代码搜索、丰富的源码控制IAM系统、管理和获取大量审查代码的新颖方式等。在这篇文章中,我们将重点介绍我们具体是如何打造Scion的。这成为了一个有趣的案例研究:Claude 的代码编写能力既是我们陷入困境的原因, 也是 我们快速构建出高质量、可扩展系统来应对的原因。 [!quote]+ 发展我们的单存档 在我们探讨我们所建立的东西之前,我们应该承认我们的工作量有多么不同寻常。毫不意外,Anthropic 比几乎所有公司都更频繁地使用 Claude 编写软件,因此我们往往是第一个看到为人类尺度设计的工具开始出现压力的。源控只是其中一个例子。虽然我们预计近期内不会有太多组织遇到这些问题,但我们怀疑不久之后,其他使用 AI 编码工具的人也会遇到类似的压力点,这也是我们想分享我们构建和学习到的东西的原因。 Git 是一个去中心化系统:每个克隆体都是完整、自包含的仓库,可以计算差异、读取历史和指责,并在完全离线时查看任何版本。对于绝大多数仓库来说,这是正确的设计,这也是git成为标准的重要原因。 随着我们的单一仓库规模扩大,它越来越不适合那个设计空间。仅我们主分支的历史就接近100GB,而 压缩版的工作 副本超过25GB。我们每天大约完成2500万次CI代码检查,还未包括开发者环境、Agent 沙盒和研究岗位。如果天真地拉回来,那每天大约会有超过600 PB的git流量。 Git 提供了处理仓库片段的工具,如浅克隆、稀疏借出和承诺远程。除此之外,对于大型单仓库还有一些标准的变通方法,比如内部的 git 镜像和存储在 blob 存储中的仓库快照(种子)。我们用过所有这些工具——在巅峰时期,我们运行了几百个内部git镜像来处理负载。这为我们争取了时间,但随着合并率的增加,操作变得越来越困难。刷新间,种子从主节点掉得越来越远,而且越来越需要小心,才能让依赖历史的操作,比如差异和责任,在部分克隆上正常工作。 退一步来看,我们注意到,像大多数公司一样,我们把git当作一个权威副本的集中系统使用,但几乎所有客户都是经纪人,且工作本身就是在线的。git 非常适合分布式离线工作的属性,随着仓库的增长,反而削弱了我们的扩展能力。所以我们问自己:如果我们设计源码控制时,考虑到 Agent 从一开始就始终在线,那会是什么样子? [!quote]+ Agent 级源控制器的原则 随着智能编码的发展,许多关于软件开发方式的常见假设正在演变。我们在构建Scion时接受了这些变化,这使我们在几个核心原则上采取了与git截然不同的方法。大型单仓库的源代码控制已有先人技术,尤其是谷歌的 Piper 和Meta的 Sapling ,因此我们能够基于他们辛苦获得的经验构建Scion。我们的原则是: 客户始终在线 。Git 假设客户端离线工作,需要完整的仓库副本。由于几乎所有客户都是 Agent 和工作,我们围绕一台始终可访问的服务器设计了Scion的客户端和协议,客户端在需要时获取数据。 客户端-服务器不对称 。在 git 中,每个客户端都能成为一个完整的服务器。在 Scion 中,服务器负责回答文件历史和责任归属的问题,创建提交,执行合并和重基,等等。客户端维护有界的本地对象缓存,在磁盘上布局工作复制文件,监控文件系统变化,并为用户提供符合人体工学的服务器操作方式。它自身计算能力非常有限,但作为交换,它在本地所需的数据要少得多。 全面的源代码控制服务可以为许多新颖应用提供动力。 而使用 git 时,需要询问仓库问题的 CI 作业或工具,比如谁最后修改了一行或两个提交的关联,必须维护仓库的本地副本,或者希望厂商特定的 API 能提供答案。而 Scion 则通过 API 暴露所有源控查询,因此很多作业根本不需要本地仓库。许多内部工具,比如我们的自动化分割和还退流水线,如果没有这种廉价的程序化源码控制访问,就无法在大规模上实用。 一切都必须是横向可扩展的。 在巅峰时期,我们运行了几百个git镜像,这大大压缩了容量,一旦仓库超出镜像磁盘或内存限制,就无法再扩展了。在 Scion 中,仓库的数据是分布式的,每个组件都可以独立扩展;即使在服务器上,也没有完全实体化的仓库副本。没有类似 packfiles(git 压缩的对象捆绑包)的对应物,因此无需仓库维护。 提交必须廉价、增量且无锁 。在 git 中,你先在本地提交,然后推送分享你的作品。在Scion中,每次提交、重基或合并都在服务器上完成,所以没有需要推送的内容,但这些操作都需要快速。创建提交并更新下游数据结构的成本必须随变更规模而定,而不是整个仓库的规模,否则服务器跟不上。Scion 的开发生命周期不鼓励使用ref(指向提交的指针,如分支和标签),但主要的引用或发布分支除外,因为所有服务器必须达成一致的 全局 状态是一个即将存在的扩展难题。 工作副本是可选的,设计上很简约 。因为我们的单仓库规模很大,而且我们每天要为CI检查数千万次代码,所以我们希望尽量避免借出。例如,对于 Scion,需要提交与合并基差别的 CI 作业,可以向服务器请求。写入也是如此:许多写工作负载也可以跳过结出,直接通过API运行。Scion的协议围绕稀疏借出(sparse checkouts),只包含客户端请求的目录,以及虚拟化结出(virtualized checkouts),按需实现文件,因此当作业需要磁盘文件时,客户端只需支付实际读取的内容费用。 [!quote]+ Scion的运作方式 理解这些原则如何在构建Scion时实际结合起来很有帮助。这些见解可以应用于其他源代码控制系统,或者更广泛地说,适用于软件开发生命周期的其他阶段。 数据结构 在Scion中,工作单元是“变更集”,即写入日志中的一条。变更集存储了你在 git 中对提交所期望的大部分内容。但 git 提交存储指向树的指针,而 changeset 存储的是相对于第一个父节点变化的文件 列表,以及 指向 blob 存储中压缩文件内容的内容寻址指针。变更集在服务器端创建,随时可用。 这种结构让我们能够接受高吞吐量的变更集,因为没有需要接受的包文件,没有锁定或跨服务器协调,也没有需要移动的引用。Scion 技术上支持引用,但由于创建和获取提交都不涉及引用,移动提交是一个对单个 Spanner 行的比较与交换,且与创建变更集分开。 变更集只记录变更的内容,所以它本身无法快速回答诸如谁最后编辑了一行或哪些提交影响了文件等问题。为回答这些问题,Scion 从变更集构建了额外的数据结构,包括专门用于文件指责和路径历史的结构,以及提交图的跳过列表。我们称所有不直接属于变更集的部分为“衍生数据”,并通过一个通用机制计算。每种类型的衍生数据都是递归定义的,因此其变更集的值是从该变更集父节点的值计算而来的。 这种机制有三个好处。首先,当新的数据结构能让某些操作更快时,我们可以很容易地添加一种新的派生数据类型。其次,对于每种类型,我们可以选择是急切计算还是推迟工作,以避免生成不需要的数据。第三,由于客户端从未看到这些数据结构的内部结构,我们可以在不更改客户端的情况下进行优化。随着系统的发展,我们多次添加新的衍生数据类型,比如用于执行复制检测或基于路径的文件搜索的新索引。 等级化的后裔 一小群 Scion 服务器为客户端所需的任何操作提供源码控制 API,如获取变更集、计算差异、寻找合并基底和获取 blob。所有源码控制数据都是内容寻址的,因此数据一旦存储就不会改变,任何服务器都可以在不与其他服务器确认的情况下缓存它。因此,服务器具有横向可扩展性,几乎不需要协调。它们本质上是大型缓存,可以实时计算衍生数据并将结果写回 Spanner。 Scion的众多用户不再需要维护自己的本地存储库。获取和维护仓库曾经是CI作业或工具的重大维护负担,尤其是涉及提交祖先和责任问题。迁移初期,在我们还没有自己的客户端、仓库格式或协议之前,Scion 只回答这些“元数据”查询。获取文件内容和实现工作副本是更耗费数据的操作,他们需要自己的设计。 Scion 的 scn 客户端在多个重要方面偏离了 git 的取用协议,因此它适合高度可扩展的架构,所需的 CPU 远少于 git 服务器。Scion 的协商不会告诉服务器客户端已有的是什么;相反,它只对客户端想要的树和斑点进行操作。从根树开始,客户端检查本地存储中缺失的树并递归请求,然后重复此过程寻找blob。每个请求都针对一个永不更改的特定对象,因此任何缓存都能响应,其架构与传统的分层缓存非常相似。该过程也高效且可重复,因为没有单一的多GB包文件响应。稀疏甚至虚拟结账不需要特别支持,因为客户端根本不会要求它不想要的树。 在舰队中,客户端通过套接字与守护进程(scion-daemon)通信,守护进程存储整个节点的对象。我们的大多数节点都需要访问 monorepo,而同一节点上的作业会重复使用大部分相同的对象。每个守护进程从定期刷新的快照开始,然后只与其区域内的树状缓存和blob缓存服务器通信,称为scion缓存。这些缓存服务器直接从内存流式传输对象,格式为守护进程将消耗的磁盘格式,因此无需花费时间计算客户端缺失的对象或执行delta压缩。当缓存缺少对象时,它会请求权威的 scion 服务器,这些服务器会根据需要从 Spanner 或云存储读取数据。 scion-daemon、scion-cache 和 scion-server 都响应该协议的相同 RPC,因此客户端无需了解缓存拓扑。理论上任何层级都可以与其他层级通信,但我们严格执行分层以隔离失败域。我们希望避免区域继承缓存的故障导致上游继承服务器不堪重负,导致整个系统宕机的情况。 该系统的每个层级缓存命中率都超过99%,且不需要长寿命状态,因此如果需要,可以轻松扩展。我们的Scion基础设施占用比之前的git镜像基础设施在CPU和内存需求上小了200倍。CI和研究岗位的代码检验速度快了两个数量级(几秒而非几分钟),这释放了舰队大量的容量;仅CI就实现了25%的CPU容量提升。客户端和缓存都无需执行仓库维护,这简化了作业的生命周期管理。 [!quote]+ 我们建造Scion的经验 我们开始构建Scion的时间大约是 Claude Mythos Preview 和 Claude Tag 内部可用的时候。这两次发布同时放大了Scion的需求,并显著加快了我们构建它的速度。 这里有一个特别引人注目的例子。年初,我们基本上手写了git到Scion的采集流程的第一个版本,作为原型。我们觉得它不错——直到我们拿到了Claude Mythos Preview的早期内部快照。我们让它重写整个系统,没有其他指令,它生成了一个内存占用减少20倍、速度提升4倍的版本,同时保留了所有关于摄取顺序和数据结构的隐式不变量。 我们在构建和运营Scion时学到了一些有趣的经验,帮助我们了解构建 Agent 规模软件的可能样貌。 小 团队快速开发将变得更加常见 。一个由七人组成的团队开发了Scion 和 Antique(我们的代码审查工具,这两者我们完全可以写一篇博客),更不用说还有半打相关系统,并在五个月内完成了全面迁移。我们做这一切时,每天合并的代码量增加了10倍。过去,开发和部署这样的源码控制系统需要公司多年迭代迁移,工程师数量更多。我们认为这种快速、灵活的迁徙未来将变得更加普遍。 工程师同样重要,但他们的工作正在发生变化。 所有参与该系统的工程师现在都会评价Claude比他们更擅 长写 代码。但我们的工程师依然提供了对高层次系统间组件和设计层权衡的宝贵理解,围绕我们想要解决的问题和我们知道需要实现的规模做出明智选择。我们发现工程师们的角色往往是告诉克劳德“不行”。Agent 有时会违反核心系统约束,以满足本不该允许的模式。这在我们的迁徙中尤为常见。例如,有多个系统试图通过线性读取提交日志来暴力破解合并到主日志,而不是询问代码审查工具。人类审阅还广泛使用对抗性审查,虽然这在很多方面都非常有效,但也可能目光短浅,因此需要有经验的工程师引导克劳德避免在假设性问题下过度设计系统部分。例如,有一次审查对信任其他内部服务过于防御,导致Claude增加了过度的验证和复杂性。我们的团队成员仍然会审核系统的所有变更请求,但他们现在更关注变更的 意图 ,而不是逐行阅读代码。 我们实现了优化和质量的显著提升 。凭借Claude能够比我们自己更快地编写大量代码的能力,Scion成为我们参与过的最经过充分测试和防御的代码库之一。即使在时间紧迫的情况下,我们也能构建出所有非平凡基础设施和源码控制交互的密闭模拟,以及模糊和复杂的速率限制。克劳德还随意发现了重要的优化——例如,对祖源查询的算法优化漏掉了我们的某个索引——这些都可能需要专家们花费数天甚至数周的分析和调整…第二天又重复了一遍。 我们为新型单一回购证券(monorepo)安全机制奠定了基础 。管理庞大单一回债的安全性、保障和合规性,与管理规模和规模同等重要。我们从一开始就考虑了这些,打造了Scion。它支持对仓库的丰富访问控制,并能够对单个目录应用权限,以保护最敏感的
- 情报分类:工作与职业机会
- 分类依据:内容涉及招聘、求职或职业发展
- 信息来源:服务器 / LINUX DO - 最新话题
- 发布时间:2026/10/14 10:07:55
- 暂无回复