Google 为何把几十亿行代码放在一个库?

本文原文连接: ruanyifeng.com/blog/2016/07/google-monolithic-source-repository.html,若有侵权,则可删除。

00 前言

《ACM通讯》有一篇论文《为何 Google 要把几十亿行代码放在一个库?》,做者是谷歌基础设施小组的工程师。做者详细讲述了Google的代码为何所有放在一个库里面。html

01 概述

谷歌最先使用 CVS 进行代码管理,1999年改成 Perforce。那时是一台 Perforce 主机,加上各类缓存机。算法

当时,全公司的代码就在一个仓库里面,后来一直沿用这种作法。因为规模不断增加,Perforce 已经没法知足需求,谷歌就开始使用本身开发的版本管理系统 Piper。数据库

Piper 架设在谷歌本身的分布式数据库系统(之前叫 Bigtable,如今更名 Spanner)之上,分布在全世界10个数据中心,保证世界各地的谷歌员工都有良好的访问速度。缓存

目前,这个代码仓库包含10亿个文件、3500万次提交记录,大小为86TB,用户达到几万人。工做日每秒有50万次请求,高峰时80万次,大部分来自自动构建和测试系统。性能优化

谷歌90%以上的代码,放在 Piper 里面。对于那些开源的、须要外部协做的项目,代码放在 Git,主要是 Android 项目和 Chrome 项目。Git 的特色是,全部历史记录都会复制到用户的本地机器,因此不适合大型项目,必须拆分红更小的库。以 Android 为例,该项目一共包含800多个独立的仓库。分布式

02 Piper 的设计

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-based development)。代码通常提交到主干的头部。这样保证了全部用户看到的都是同一份代码的最新版本。

“主干开发”避免了合并分支时的麻烦。谷歌通常不采用分支开发,分支只用来发布。大多数时候,发布分支是主干某个时点的快照。之后的除错和功能加强,都是提交到主干,必要时 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 总结

单一代码仓库,适合提倡透明开放的大型软件公司,不适合小公司和有大量私密代码的公司