Google 为什么把几十亿行代码放在一个库?
本文原文链接:ruanyifeng.com/blog/2016/07/google-monolithic-source-repository.html , 如有侵权 , 则可删除 。
00前言
《ACM通信》有一篇论文《为什么Google要把几十亿行代码放在一个库?》 , 作者是谷歌基础设施小组的工程师 。 作者详细讲述了Google的代码为什么全部放在一个库里面 。
01概述
谷歌最早使用CVS进行代码管理 , 1999年改为Perforce 。 那时是一台Perforce主机 , 加上各种缓存机 。
当时 , 全公司的代码就在一个仓库里面 , 后来一直沿用这种做法 。 由于规模不断增长 , Perforce已经无法满足需求 , 谷歌就开始使用自己开发的版本管理系统Piper 。
Piper架设在谷歌自己的分布式数据库系统(以前叫Bigtable , 现在改名Spanner)之上 , 分布在全世界10个数据中心 , 保证世界各地的谷歌员工都有良好的访问速度 。
目前 , 这个代码仓库包含10亿个文件、3500万次提交记录 , 大小为86TB , 用户达到几万人 。 工作日每秒有50万次请求 , 高峰时80万次 , 大部分来自自动构建和测试系统 。
谷歌90%以上的代码 , 放在Piper里面 。 对于那些开源的、需要外部协作的项目 , 代码放在Git , 主要是Android项目和Chrome项目 。 Git的特点是 , 所有历史记录都会复制到用户的本地机器 , 所以不适合大型项目 , 必须拆分成更小的库 。 以Android为例 , 该项目一共包含800多个独立的仓库 。
02Piper的设计
2.1结构
整个仓库采用树状结构 。 每个团队有自己的目录 。 目录路径就是代码的命名空间 。 每个目录都有负责人(owner) , 他负责批准该目录的文件变动 。
2.2权限控制
Piper支持文件级别的权限控制 。 99%的代码对所有用户可见 , 只有少部分重要的配置文件和机密的关键业务 , 设有访问限制 。
如果机密信息不小心放上了Piper , 文件可以被快速清除 。 并且 , 所有的读写都有日志 , 管理员能够查到谁读过这个文件 。
2.3工作流
Piper的工作流(workflow)如下图 。

文章图片
开发者先创建文件的本地拷贝 , 这叫做”工作区”(workspace) 。 完成开发后 , 工作区的快照共享给其他开发者进行代码评审 。 只有通过了评审 , 代码才能合并到中央仓库 。
2.4客户端
大多数开发者通过一个叫做CitC的客户端 , 访问Piper 。 开发者通过CitC浏览和同步Piper上的文件 , 但是编辑和修改是在自己工作区 , 里面只保存有变动的文件(一个工作区一般不超过10个文件) 。 CitC带有云储存机制 , 每个工作区就是云上的一个目录 。 通过代码评审以后 , 这些文件才从Citc合并进Piper 。
2.5主干开发
Google采用”主干开发”(trunk-baseddevelopment) 。 代码一般提交到主干的头部 。 这样保证了所有用户看到的都是同一份代码的最新版本 。
“主干开发”避免了合并分支时的麻烦 。 谷歌一般不采用分支开发 , 分支只用来发布 。 大多数时候 , 发布分支是主干某个时点的快照 。 以后的除错和功能增强 , 都是提交到主干 , 必要时cherry-pick到发布分支 。 与主干长期并行的开发分支 , 在谷歌极少见 。
由于不采用''分支开发'' , 谷歌引入新功能 , 一般在代码中使用开关控制 。 这避免了另起一个分支 , 也使得通过配置切换功能变得容易 , 一旦新功能发生故障 , 很容易切换回旧功能 。 等到新功能稳定 , 再彻底删除旧代码 。 谷歌有类似A/B测试的路由算法 , 评估代码的表现 , 由于存在配置开关 , 这种测试很容易实现 。
2.6代码评审
所有代码合并进仓库之前 , 都必须进行代码评审 。 大部分评审对所有人开放 , 任何谷歌员工都可以对代码提意见或者提交变动 。
代码评审的依据是《Google代码风格指南》 。 谷歌有一个叫做Critique的工具 , 可以查看每一行代码的历史演变 。
2.7自动测试
评审完成后 , 会自动运行测试 。 通过测试以后 , 代码就合并进了Piper仓库 , 整个过程不需要人工干预 。

文章图片
03单一代码仓库的优点
(1)统一的版本
整个公司的代码 , 有统一的版本和路径 , 不存在找不到文件的最新版本这样的问题 。
(2)广泛的代码共享和复用
任何人都可以浏览和使用全公司的代码 , 这大大促进了代码的共享和复用 。
(3)简化的依赖管理
如果你是库文件或者API的作者 , 因为所有人的代码都在一个库里面 , 所以很容易找到依赖你的所有下游代码 。
每当代码变动 , 所有依赖你的代码都会自动构建 。 如果有大量的构建失败 , 那么系统会自动撤销这次提交 。 这样也保证了所有代码依赖的都是最新版本 , 避免依赖不同的版本所导致的冲突 。
另外 , 由于代码的边界很清楚 , 所以不会发生循环依赖 。 而且 , API的作者也很容易发现 , 别人怎么使用他的API 。
(4)原子性变动
由于每次代码变动所导致的影响 , 都在一个仓库里面 , 所以都属于原子性的变动 。 因此 , 很容易撤销 , 或者预先测试它所造成的影响 。
为了防止错误提交 , 谷歌引入了”预提交”(即在提交之前 , 先分析一下依赖它的代码是否会构建失败) 。
(5)大规模代码析构
单一代码仓库为查找和分析代码 , 提供了巨大的方便 。
Google的静态分析引擎Tricorder定时运行 , 对代码进行分析 。 比如 , C++11标准公布以后 , 很容易找到所有需要改进的变量声明语句 , 进行性能优化 。 该引擎还对许多错误提供''一键修正''的功能 , 同时产出大量的统计数据 。
此外 , 编译器团队也会对不同语言的所有代码进行分析 , 找出不合理的代码和过时的API 。
04单一代码仓库的缺点
单一代码仓库的主要缺点是 , 所有工具都必须自己写 , 因为市场上没有能够管理这种规模的代码仓库的软件 。
05总结
【Google 为什么把几十亿行代码放在一个库?】单一代码仓库 , 适合提倡透明开放的大型软件公司 , 不适合小公司和有大量私密代码的公司

文章图片
推荐阅读
- 养老金|2021年上半年办理退休,养老金核算的这些知识要把握
- 兔子|兔兔这么可爱,为什么要吃屎?
- 茶香四溢的慕斯蛋糕
- 精河县精深加工,把每颗枸杞都“吃干榨尽”!
- 显微镜|假如人类可以把显微镜提升到40亿倍,是不是全新的宇宙观?
- 埃及金字塔|探秘尼罗河|为什么会有人觉得,埃及金字塔是伪造的?
- 入秋后,手把手教你蒸馒头,不塌陷不回缩,蓬松柔软,好吃又劲道
- 芽芽泡|这种全身是刺的野草,80后曾把它当零食,3月正当季,你吃过吗?
- 减肥|较真丨减肥产品含违禁药再被曝光,为什么说滥用这些产品是在玩命?
- 酿酒|用真全粮酿酒机器做酒,为什么发酵时间越长口感越好?
