注:本文英文原文google开发者工具组的博客上[需要FQ],以下是我的翻译,欢迎转载,但请尊重作者版权,注名原文地址。

之前两篇文章分别介绍了Google 分布式软件构建系统Blaze相关的为了提供对存储在云端的源码的访问支持而定制的文件系统构建系统是如何工作的。这篇文章在前两篇文章的基础之上介绍了一个在大规模集群上面分布式高效率执行构建步骤的系统[译者注:就是Blaze]。正如你看到的,源文件系统和构建系统的细节对于我们实现快速高效的分布式构建是非常重要的。所以在介绍构建步骤如何分布式执行的机制之前,来关注几个重点。

首先,构建系统是基于内容的,系统内部对于输入和输出是通过基于内容的摘要来标记的,而不是文件和时间戳(例如Make)。这意味者通过比较内容摘要就能知道内容是否是相同的,构建系统在根据行为图来执行构建操作时,会把这些摘要在内部记录下来。在构建过程中为大量的源代码计算内容摘要会很耗时,主要时间都花在读取文件上。通过在内容提交的时候计算并存储摘要就可以避免这个问题,之后直接通过文件扩展属性来提供给构建系统。

另外,构建系统通过读取BUILD文件来构建一张依赖关系的图,然后使用依赖关系图去构建一个 构建行为 或构建步骤的图。通过使用行为的输出作为其他行为的输入来构建这个依赖关系图。依赖关系必须是完整指定的,而且不能有动态的依赖检测。内容摘要和指定的完整依赖意味着行为可以通过函数来表示。在这个 函数模型中 ,函数的输入是内容摘要和环境(环境变量,命令行选项),函数是把输入转化成输出的工具或脚本,函数执行结果就是输出。这些函数式的构建行为是构建工作的原子单元,从输入转换到输出是对系统透明的。这意味着构建行为是不用知道语言和工具的,例如,可能是编译C++单元,编译java文件,链接成一个可执行文件,甚至是跑一个单测。

下面是一个行为图的举例。行为的输出,例如CC行为输出是search.o,成为其他行为(本例子中是LD)的输入。

第三,我们需要每个构建行为只能使用它显示声明的输入。这意味者同样的行为,使用同样的输入执行多次,结果在二进制级别是相同的。这保证了两次构建时的输入内容如果完全相同,那就不需要再去执行本次构建行为,因为构建结果不会改变。这似乎听起来是合理的,但实际上一个行为可能依赖于除了显示声明的输入文件之外的东西,例如系统头文件的内容或者是当天的时间(考虑下由C语言预处理展开的__DATE__宏,或者是每个jar文件中嵌入的时间戳)。我们让工具来执行 不受外界影响 的行为并对一些文件类型做预处理来覆盖时间戳来避免这个问题。

现在我们继续介绍如何使用这些函数式的行为来执行分布式构建

每个构建行为是自给自足的,原子的,所以是 便携的,可以带着输入发送到其他机器上执行。这对于Google很有意义,因为我们正好在数据中心有很多机器,意味着我们可以把构建行为分发到成千上万台机器上去执行。这种模型下所有的构建行为都可以分布式执行,并发度只受行为树的宽度限制。

在很多机器上分布式的执行构建行为使得构建变快,但是我们发现机器上执行的工作都是重复的,因为很多开发人员构建的代码都是相同的。构建行为自身的函数式特性--相同的输入条件下,输出也是一模一样的--意味者我们可以很容易并正确地缓存和复用构建结果。我们计算整个请求(命令行和输入)的摘要来做为缓存的键,所以不可能“疏忽”了某些东西而错误的命中缓存结果。还记得输入文件是通过内容摘要来描述的吗?这表示即使对于巨大的内容,计算缓存的键也是相对容易的。当构建行为已经准备好远程执行时,首先计算缓存的键。如果没有命中缓存,这个行为会被执行并会在结果返回给用户的时候进行缓存。当命中缓存,就直接使用缓存中的结果。为了让缓存的结果看起来是真正执行过的,我们也会把标准输入和标准错误输出也缓存起来然后进行回放。

当改动提交到代码源里,进行第一次构建时,每个改动点影响的行为会耗时久一些,因为这些行为需要重新执行,但因为构建行为是分布式并发执行的,所以这种耗时并不是很显著的。在很多情况下,例如C++中空格和注释的改动,这种不同的输入仍然产生二进制级别上相同的结果。由于构建系统是基于内容的,所以这种情况会导致后续的行为依然能够命中缓存,所以提供了另外一种避免重复构建的方法。整体来说,最后缓存命中率超过90%。这意味即使是“干净”地重新构建也是大部分利用的之前构建的结果,所以会非常快。也可以这样理解,这些代码的改动没有影响到最终发布的库和可执行文件。

分布式构建并重复利用构建行为是如此成功地加速了构建过程,以至于我们不可避免的遇到了另外的问题。一个大工程的干净的构建可能会产生几个G的输出,这些构建通常只花费了数分钟而我们每天构建上万次,这导致分布式构建产生的数据对我们的网络和本地磁盘I/O造成了相当大的压力,本系列最后一篇会介绍我们是如何解决这个问题的。

回到本系列目录

Google分布式构建软件之三:分布式执行构建步骤的更多相关文章

  1. Google分布式构建软件之二:构建系统如何工作

    分布式软件构建第二部分:构建系统如何工作 注:本文英文原文在google开发者工具组的博客上[需要FQ],以下是我的翻译,欢迎转载,但请尊重作者版权,注名原文地址. 上篇文章中提到了在Google,所 ...

  2. Google分布式构建软件之四:分发构建结果

    注:本文英文原文在google开发者工具组的博客上[需要FQ],以下是我的翻译,欢迎转载,但请尊重作者版权,注名原文地址. 之前的文章,介绍了Google在分布式构建软件过程中,如何把构建过程分发到许 ...

  3. Google分布式构建软件之一:获取源代码

    本文原文在google开发者工具组的博客上[需要FQ],以下是我的翻译,欢迎转载,但尊重作者版权,注名原文地址. 在Google,所有的产品都是在主干上开发的.这样的好处:每个人都可以查看和修改代码, ...

  4. Dubbo+zookeeper构建高可用分布式集群(二)-集群部署

    在Dubbo+zookeeper构建高可用分布式集群(一)-单机部署中我们讲了如何单机部署.但没有将如何配置微服务.下面分别介绍单机与集群微服务如何配置注册中心. Zookeeper单机配置:方式一. ...

  5. Spring3.0+Hibernate+Atomikos集成构建JTA的分布式事务--解决多数据源跨库事务

    一.概念 分布式事务分布式事务是指事务的参与者.支持事务的服务器.资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上.简言之,同时操作多个数据库保持事务的统一,达到跨库事务的效果. JTA ...

  6. spring3.0+Atomikos 构建jta的分布式事务 -- NO

    摘自: http://gongjiayun.iteye.com/blog/1570111 spring3.0+Atomikos 构建jta的分布式事务 spring3.0已经不再支持jtom了,不过我 ...

  7. spring3.0+Atomikos 构建jta的分布式事务

    摘自: http://gongjiayun.iteye.com/blog/1570111 spring3.0+Atomikos 构建jta的分布式事务 spring3.0已经不再支持jtom了,不过我 ...

  8. 纯干货!华为软件开发云编译构建之Maven

    一.Maven介绍 Maven是一个项目管理和整合的工具.Maven为开发者提供了一套完整的构建生命周期框架.开发团队基本不用花多少时间就能自动完成工程的基础构建配置,因为Maven使用了一个标准的目 ...

  9. jenkins执行构建并查看结果

    继完成构建项目配置http://www.cnblogs.com/yajing-zh/p/5111060.html后,则要执行构建. 回到jenkins主页之后,我们看到一个新建的项目显示出来: 点击进 ...

随机推荐

  1. mybatis Caused by: org.apache.ibatis.reflection.ReflectionException: Error instantiating class .. with invalid types () or values (). Cause: java.lang.NoSuchMethodException: ...<init>()

    如果有带参数的构造器,编译器不会自动生成无参构造器.当查询需要返回对象时,ORM框架用反射来调用对象的无参构造函数,所以会导致此类异常 public Test(){ }

  2. SQL SERVER 数据导出JSON

    执行下面的存储过程: SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE[dbo].[SerializeJSON]( @ ...

  3. html5吹牛扯淡篇,闲话内容。

    09年提出对媒体查询的草案,到今天的广泛运用,w3c带我们走进了个性化定制的殿堂.这些之所以会被认可会被写进世界级标准,因为他越来越适应广大用户的需求,需求就像一条锁链带动或者牵引整个互联网开发工作. ...

  4. mongoose数据库连接和操作

    var mongoose = require('mongoose') mongoose.connect('mongodb://localhost:27017/hometown'); var db = ...

  5. CharacterEncodingFilter-Spring字符编码过滤器

    通过源码可以看到在web.xml配置CharacterEncodingFilter 时,可以配置两个参数:encoding和forceEncoding : encoding:编码格式: forceEn ...

  6. 关于用display:table让元素居中的小结

    我们都知道让元素垂直居中有一种简单的方法:给需要居中的元素用一个父级包起来,并给它设置样式:display:table:同时给这个父级设置好高度:再给需要居中的元素一个display:table-ce ...

  7. 文档:网络通讯包结构(crc校验,加解密)

    一直想把这个流程整理一下. 包结构: 包 对(datacrc+protoID+dataSize)组成的byte[] 进行crc计算而得到 对(数据内容)进行crc计算而得到 协议号 数据内容的字节长度 ...

  8. javascript Date format(js日期格式化) (转)

    方法一:这个很不错,好像是 csdn 的 Meizz 写的: // 对Date的扩展,将 Date 转化为指定格式的String // 月(M).日(d).小时(h).分(m).秒(s).季度(q) ...

  9. 懒加载lazyload

    什么是懒加载 懒加载就是当你做滚动到页面某个位置,然后再显示当前位置的图片,这样做可以减少页面请求. 懒加载:主要目的是作为服务器前端的优化,减少请求数或延迟请求数,一些图片非常多的网站中非常有用,在 ...

  10. ACCEPTANCE CRITERIA FOR USER STORIES

    One of the teams I have recently coached quickly got a grasp of how to phrase user stories but found ...