企业项目管理、ORK、研发管理与敏捷开发工具平台

网站首页 > 精选文章 正文

实战百万文件monorepo仓库的优化(实战百万文件monorepo仓库的优化研究)

wudianyun 2025-05-08 07:00:46 精选文章 15 ℃

现在开发版本管理和DevOps自动流程时代,Git成了每一个组织生产栈中不可忽视的一环。然而我们知道Git也不是万能,在面对大文件、二进制文件以及大量文件仓库时,会具有巨大的性能压力。然而在实际的生产中,这些却不可避免,如何优化Git成了一个迫切要解决的问题。

本文我们就以Canva的开发团队的实际经历为例学习如何在大量文件的monorepo中优化Git的性能。

概述

尽管优劣各有,但是综合权衡利弊,Canva团队还是决定采用了Git monorepo模式。

Canva核心代码库自2012年第一次提交以来,存储库的大小和流量都在不断快速增长。在过去的10年里,项目的代码量从刚开始的几千行增加到2022年近6000万行。每周都有数百名工程师的数千次PR、数千次的提交,近一百万行代码变更,涉及的文件多达50万个。

这种几何式的扩张显著降低了git性能,比如简单一个git status命令,运行时间也越来越长。在一个新的克隆上Canva monorepo,git status平均需要10 秒,而git fetch由于工程师合并的更改数量。由于DevOPS工作流程中git的重要性,每天多次运行这些命令导致工程师每天拥有的总生产时间严重减少并且影响到可以进行上下文切换,从而进一步减少代码效率。

解决方案

当然该问题由来已久,很多组织都遇到过,并且有很多可以借鉴的方法可供参考。Github 和Dropbox的工作以及很多git本身的改进提供了很多资源来提高git的性能。以及Canva企业内部本身的大量探索等最终形成了一个自动化脚本将其作为工程师日常工作流的一部分:

首先,为了减少git查找更改所需的工作量,使用fsmonitor 与Watchman挂钩,在每次运行命令时都会存储存储库以捕获发生的更改,而无需进行全盘文件扫描。还启用了feature.manyFiles ,使在git底层未跟踪的缓存可跳过目录以及尚未修改的文件。

Git还有一个内置命令优化存储库的数据,加快命令速度并减少磁盘空间。此功能默认情况下并未启用,可以将其注册为每日和每小时的计划任务中去。

仓库特征

深入研究monorepo内的文件类型,发现.xlf文件几乎占了文件总数的70%。这些.xlf 文件是生成的并包含已翻译的每个语言环境的字符串。尽管他们存放在monorepo中,但他们是自动生成的,所以永远不会需要求人工手动编辑。然而,却无法彻底删除或忽略这些文件,因为它们仍然需要翻译系统运行顺利。一个最佳解决方案是告诉git不要使用以下命令将它们填充到工作树中稀疏checkout,在本地忽略它们,同时仍然从monorepo中的其他来源跟踪其变化。实际上,必须包含其他en-AU区域设置的字符串构建系统的一部分可以工作,但这是一个可以忽略不计的差异。尽管这些翻译被忽略,本地环境仍然运行与特殊的en-psaccent伪本地化语言环境,所以工程师仍然有本地化意识要求。

此功能默认情况下对monorepo 的单独克隆进行了以下实验。的默认设置,未进行其他优化之前。

可以将稀疏checkout功能更进一步。工程师通常在小团队中工作并与更小的子集互动。例如,一名从事编辑器工作的前端工程师不太可能修改与搜索或计费服务器相关的代码。如果工程师可以告诉我们他们通常做什么,就可以制作一个包含运行所需的所有依赖项的签出模式在本地测试他们的代码,同时保持checkout尽可能小。

Canva monorepo 使用Bazel作为选择的构建系统,在其中定义构建目标(主页、搜索服务器、导出按钮等)及其依赖关系。这意味着给定Bazel目标,可以准确地确定构建、运行和测试并排除需要哪些文件其余的通过查询Bazel依赖图来完成。 在实践中,这需要更多的启发式方法,因为并非所有内容都被挂钩到Bazel构建图,需要解析符号链接,但这些都是可以解决的边缘情况。下表显示了一些示例配置以及它们如何影响到checkout时间的。

后端服务往往模块化得更好并且可以大部分运行独立,而前端页面则不然。这是由于各种诸如typescript配置文件、linting设置方式等原因,并且工具和网页在编写时并没有考虑到稀疏checkout,假设所有文件始终存在。 这些配置在翻译文件之上提供增量改进让每个工程师都可以自由选择。

但是使用稀疏checkout也存在问题。

首先,现在跟踪的文件并未实际填充在磁盘上,因此无法搜索或与之交互。意外更改或错误的合并冲突可能会使这些文件处于错误状态(例如,当两个PR更改要翻译的同一字符串时并产生冲突,这些文件在必须手动解决)。这些是工程师在工作流程中必须注意的情况。

每个git checkout命令都会产生开销来检查是否应填充或忽略更新的文件。虽然这开销并不大,具有简单的模式,例如忽略.xlf 文件,它对于更复杂的情况变得重要。

最终方案

结合现有的monorepos和git配置最佳实践并忽略翻译文件,让git status时间减少到3秒和2秒(带缓存)。虽然这对工程师来说是更好的体验与完全没有改变相比,还有很长的路要走这个数字随着monorepo和工程师数量的不断增长。 这些优化为可实现的目标设定了基线专门为大型存储库制作的配置。但要量化git性能对工程师生产力的影响以及进一步排除故障并优化它,需要能够收集来自git操作遥测数据。

Git已经提供trace2方法,通过它可以按照格式捕获并发送到存储进行分析。团队不断发展内部名为Olly的工具就是用来执行此操作的,捕获操作时间、故障及其原因、跟踪新分支的创建等等。通过监控整个组织中git的性能,反馈对git配置所做的变更。

通过这种遥测,现在可以具体量化影响git性能对工程师的影响,关注痛点(git fetch from 上图),并进一步深入了解每个操作。

捕获的git fetch跟踪:

深入研究索引包操作,我们可以获得正在传输的包、对象和字节的数量:

此外,由于git最近存在漏洞 ,致力于向所有工程师提供已知版本的git默认情况下正确的配置,确保每个人都能获得最新的安全补丁和性能改进。

总结

Canva团队遇到的问题很典型也很棘手。他们通过一些常规性的适用于大多数的Git优化技巧进行了优化,同时从他们仓库特征出发,直到面对他们特有问题的稀疏checkout方法来进行针对性优化(通常是最有效的)。面对更进一步的优化和可能面对的问题,他们利用Git trace2功能对其内部操作进行遥测,量化统计每一个操作,这才是真正的灵丹妙药,也是每一个组织可以借鉴的“万能”方法。

Tags:

最近发表
标签列表