说到构建工具,不同语言技术栈的人,想起的构建工具不同。
Java程序员想到的是Maven,前端程序员想的是NPM或者Webpack、Android程序员想到的是Gradle、Rust程序想到的是Cargo、C++程序员想到的是Make等等。
然而这些工具在Bazel面前,层次有些低。所以,我愿称Bazel是构建工具之王。
P.S. Android平台的构建,2020年已经开始了迁移到Bazel的工作。 具体地址:https://blog.bazel.build/2020/11/12/aosp_migrating_to_bazel.html
Bazel介绍 Bazel是Google在2015年开源的一款构建工具。
目前使用Bazel的知名公司有:Esty、Canva、Databricks、Dropbox、Huawei、Line、LinkedIn、Stripe、Twitter、Tinder、Uber、VMware、Wix等。具体可以看:https://bazel.build/community/users 。
其中Twitter是从自家的Pants迁移到的Bazel的,具体迁移过程介绍:https://opensourcelive.withgoogle.com/events/bazelcon2020/watch?talk=day1-talk2
Facebook使用的是其自研的Buck2,但是,其与Bazel使用的是相同的远程执行的API。
除了公司,某些著名的开源软件也使用Bazel构建,包括自动化测试领域的Selenium,AI领域的TensorFlow,容器编排领域的Kubernetes等。具体还有:https://bazel.build/community/users#open-source-projects-using-Bazel
相对于其它构建工具,它的显著的特点有:
支持多语言; 支持远程分布式构建; 支持增量构建; 支持强大的密闭性; 支持构建缓存; 支持并行构建。 假设存在一个复杂的软件工程 假设存在一个软件工程中,它包含5部分:Web前端、Android端、Java后端、Go后端、嵌入式端。
作为Java后端的程序员,他们修改了一个API。但是他作为个人,他无法预知到底发生了哪些影响。
所以,他把这个问题交给了持续集成(CI),让它去发现集成问题。
在过去很长一段时间里,行业里只有一种CI模式,我称之为传统的CI模式。
殊不知,还有另一种模式。
传统的CI模式 目前行业里比较传统的CI架构,通常如下: 在这样的架构下,实现CI的步骤如下:
开发人员提交代码; Gitlab检测到开发人员提交代码,然后触发Jenkins controller执行; Jenkins controller根据该代码仓库预先设计的pipeline执行; Jenkins controller根据pipeline中的任务所需要的构建环境,将任务分配给不同的Jenkins agent; 在agent构建完成后,将制品release到制品仓库中。 如果开发者希望验证自己写的代码,就必须将代码commit到Gitlab中。因为整个验证环境被定义在CI环境的Pipeline中。而且这个过程,越大的工程,集成速度越慢。开发者也无法在本地进行全量验证。
作为Pipeline的维护者,他需要清楚知道哪些任务是可以并行执行的,并手工配置并行,这样才能加快构建速度。比如前端构建和后端构建可以并行进行。
也就是说在传统的CI模式下,开发者的效率会随着软件的规模越大而降低。换句话,这样的模式,开发效率无法scale。
案例 希望以下案例可以给你一个感性的认知。下图是Google在2010年到2015年的周commit数量。绿线代表commit总数,黄线是人数。我们取离我们最近的2015年的数据来讨论。2015年的代码量如下: 在这个代码量下,每周能达到300左右的commit。如下图: 根据持续集成的原则,每一个commit都必须构建通过。20亿行代码一次全量构建需要多久?
我们以一个开源项目作参考。apitable是一个开源的数据表格项目,它有200万左右的代码,全量构建一次需要20分钟左右。那么,根据不准确的类推,20亿行代码,全量构建一次需要:20/2,000,000 * 2000,000,000=200,000,000分钟,也就是13天左右。
在传统的CI模式下,是尽量避免执行全量构建这样庞大的代码量的。所以,传统CI模式下,通常是多仓库模式管理代码。
那么Bazel呢?Bazel如果真要构建这样庞大的代码量,估计也够呛。但是由于Bazel天然支持并行构建、构建缓存和增量构建,所以,Bazel通常不会遇到真正意义的全量构建的情况。
为什么其它公司不使用Bazel 也许有人会问:为什么阿里2018年新增的代码行(https://zhuanlan.zhihu.com/p/54435171)就有12亿,不也没有使用Bazel吗?
这个是一个好问题。
但是,无法简单的回答这个问题,而是需要深入到各自组织内部才能分析清楚。个人觉得可以从以下维度分析:
在代码仓库上工作的人员的规模:同样的代码量,不同的组织需要不同数量的人维护; 代码管理方式:阿里使用多仓库的管理办法,不需要统一的版本号; 持续集成的程度不同:阿里可能不需要对每一个commit跑一次全量。 为什么Bazel会颠覆你对CI的认知 Bazel是如何解决传统CI模式下开发效率无法scale的问题呢?其主要通过它的六个特性来解决。
首先,Bazel支持远程分布式构建。
在一个使用Bazel构建的仓库中,开发者写好代码后,不用commit代码到Git仓库,只要在本地命令行执行bazel run --remote_executor=grpc://localhost:8980 //... ,代码仓库中所有构建和测试任务都将运行在远程执行服务器。远程执行服务器越多,构建速度越快。
这一特性可以明显地提高开发者本地的开发效率。因为开发者在本地就可以执行全量构建和全量测试。
传统CI模式下,无法提升开发者本地的开发效率。
第二,Bazel支持增量构建和增量测试(精准测试)。
开发者在本地执行build命令时,Bazel检测出修改了a.java文件,所以,Bazel只将构建a.java的任务及其相关的构建任务给远程执行服务器执行。这就是增量构建。
如果开发者执行test命令,Bazel则能检测出被影响的测试,然后只运行这些测试。其实这就是精准测试了。在Bazel中,精准测试实现起来并不难。
传统CI模式下,它是不关心增量构建和增量测试的。所以,每次运行都是全量。这是一种极大的浪费。
...