Gradle Build Cache测试版作用和工作原理概述

611 阅读8分钟

Gradle 3.5中引入,以减少构建时间。

它是做什么的?

构建缓存在本地重用Gradle任务的输出,并在机器之间共享任务输出。在许多情况下,这将加快平均构建时间。

构建缓存是对Gradle的增量构建功能的补充,它可以优化尚未构建的本地变化的构建性能。许多Gradle任务被设计成增量的,因此如果任务的输入和输出没有变化,Gradle可以跳过这个任务。即使任务的输入发生了变化,有些任务也可以只重建发生变化的部分。当然,这些技术只有在已经有以前本地构建的输出时才会起作用。在过去,在新的签出上进行构建或执行 "干净 "的构建需要重新从头开始构建一切,即使这些构建的结果已经在本地或另一台机器上(如持续集成服务器)创建。

现在,Gradle使用任务的输入作为键来唯一地识别一个任务的输出。启用了构建缓存功能后,如果Gradle能在构建缓存中找到这个键,Gradle将跳过任务执行,直接将缓存中的输出复制到构建目录中。这可能比再次执行任务要快得多。

特别是,如果你使用的是持续集成服务器,你可以配置Gradle将任务输出推送到一个共享的构建缓存中。当开发者构建时,已经在CI上构建的任务输出被复制到开发者的机器上。这可以大大改善开发者的本地构建体验。

当使用本地构建缓存时,每当你切换分支时,Gradle可以跳过任务执行,从本地缓存中提取之前的输出,而不是重新构建项目的大部分内容。

它是如何工作的?

一个可缓存的Gradle任务被设计成把所有能影响任务输出的东西都声明为输入。Gradle通过对一个任务的所有输入进行散列计算出一个建立缓存的密钥。该构建缓存密钥可以唯一地识别该任务的输出。这是每个任务实现的可选功能,所以并不是每个任务都是可缓存的,也不是每个任务都需要缓存。几个内置的Gradle任务(JavaCompile,Test,Checkstyle )启用了缓存,以加快典型的Java项目。

一个任务的构建缓存键会考虑到:

  • 任务通过注解(如@InputFiles )或运行时TaskInputsAPI定义的所有输入的值。
  • 任何文件输入的内容(和相对路径)。
  • 任务的classpath,其中包括任何插件和使用的Gradle版本。
  • 任何任务动作的classpath,其中可以包括构建脚本。

当启用构建缓存功能时,Gradle会在任务未更新时检查任何已配置的构建缓存是否包含与任务的构建缓存键相匹配的内容。 如果Gradle没有找到匹配的内容,任务就会正常执行。执行后,Gradle会收集任务的所有输出,并把它们推送到构建缓存中,如果配置了这样做的话。 如果Gradle确实找到了匹配,任务的输出就会被删除,之前的输出会被复制到输出目录中。

它有实际使用价值吗?

自2016年11月以来,我们一直在为Gradle CI构建使用构建缓存。我们也有一些合作伙伴一直在他们的构建中尝试使用构建缓存。我们不能直接分享他们的数据,但他们在CI和开发者构建中看到了与我们类似的改进。平均来说,我们看到每次提交的总时间减少了25%,但有些提交的情况甚至更好(减少了80%),中位数的构建时间减少了15%。

image.png

这里再看一下Gradle的缓存和非缓存构建之间花费的分钟数。 你可以看到,对我们来说,在360分钟的构建中,减少的时间转化为大约90分钟。

image.png

构建缓存是一个通用的功能,当它可以避免重新执行一个任务时,所以大大小小的构建都能以某种方式受益。你的项目的结构将影响你能获得多少整体收益。如果你的项目由单一的单体模块组成,Gradle的其他功能也可能有帮助,比如增量编译复合构建。我们会在未来的博文和Gradle峰会上提供更多关于如何最大限度地利用构建缓存的信息。

此刻开始提升

Gradle 3.5版本是第一个包含构建缓存功能的版本。

我们期望在下一个版本中,构建缓存功能能够普遍使用,但我们希望每个项目都能尝试一下构建缓存的测试版。要做到这一点,我们希望你能为我们做3件事。

1) 在一个简单的项目上试试

升级到3.5之后,选一个简单的Java项目并运行:

gradle --build-cache clean assemble
gradle --build-cache clean assemble

第二次构建应该会更快,因为有些任务的输出是在第一次构建中重复使用的。这些输出将从你的本地构建缓存中提取,该缓存位于你的 GRADLE_USER_HOME 中的一个目录。

2) 尝试在机器之间共享输出

为了使用共享的远程缓存,我们提供了一个推荐的配置,使用你的持续集成构建来填充一个共享的构建缓存,并允许所有开发人员从该构建缓存中提取。

你需要一个远程构建缓存后端,以便在开发者之间共享。 我们提供了一个构建缓存节点docker镜像,它可以作为远程Gradle构建缓存运行,并可以与Gradle Enterprise连接,进行集中管理。 该缓存节点也可以在没有安装Gradle Enterprise的情况下使用,但功能受到限制。

3) 给我们反馈

如果你有反馈,我们很愿意听到。如果你有一个构建扫描可以分享,那就更好了。

我们很高兴能在Gradle 3.5中推出Gradle Build Cache功能以获得反馈,但我们知道要使Build Cache稳定且性能良好,我们还需要做更多工作。我们有一些已知的问题,你应该在GitHub上提出新问题之前检查一下。

目前,在不了解风险的情况下,我们不建议你在生产构建中启用构建缓存。有一些已知的问题会导致你的构建失败或产生不正确的输出,但你对问题类型或成功的反馈对构建缓存功能的成熟非常有价值。你可以在你的构建中配置构建缓存,并通过设置org.gradle.caching=true ,或用--build-cache ,在不影响所有构建的情况下试着启用它。

对于Gradle的构建缓存,我们使用了一个单独的CI作业来运行一个启用了构建缓存的构建。这使我们能够比较相同变化的情况下,使用和不使用构建缓存的构建时间。

感谢和发展蓝图

在尝试了构建缓存后,你可能会有一些疑问,为什么你的构建中的更多部分不能被缓存。无论您使用的是哪种构建缓存后端,Gradle Enterprise 2017.2都带有通过收集数据了解构建缓存使用情况和行为的功能,无论构建缓存是否启用。构建扫描会跟踪一个任务没有被缓存的原因。如果一个任务有特殊的问题,比如它没有输出或者没有启用缓存,那么它可能不会被缓存。你可以在构建扫描的时间轴上搜索这些原因中的每一个。

在未来的Gradle和Gradle Enterprise版本中,我们会收集更多与构建缓存和任务可缓存性相关的信息,以便更容易诊断出构建失败或构建缓存性能不佳。

对于下一个版本,即Gradle 4.0,我们打算把重点放在让所有表现良好的构建都能安全启用构建缓存上,并为Gradle不能安全缓存任务输出的情况提供反馈。 这也意味着我们将提供一个行为良好的本地构建缓存和一些验证检查。

在之后的版本中,我们打算花时间来扩展我们的文档和Gradle指南,以使你更容易缓存更多的任务和开发对缓存友好的任务。

感谢你一直以来的帮助和支持。请考虑通过我们上面概述的三个步骤,用构建缓存让你的构建更快