• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

搭建自己的Gradle Build Cache Service(阿里云OSS)

武飞扬头像
近地小行星
帮助15

Gradle深入解析 - Task原理(执行篇)中分析过gradle的缓存机制,知道gradle有本地和远程缓存的区分,它会记录下task的输入输出,可以从缓存中恢复输出来避免重新执行,以加快构建速度,那么我们如何来使用remote build cache部分呢?

使用remote build cache有2种方式

  1. dockerjar包的方式运行
  2. 自己写一个build cache service

2种方式有什么区别呢?
个人感觉第一种比较适合小团队,小团队人数不多,一起开发一个项目,docker运行服务在一个服务机器上就行,对于大型团队来说,每个项目都配置一次docker比较麻烦,也不容易将不同团队数据隔离
自己写一个插件来实现build cache service可以解决这个问题,build cache service和自己的OSS服务器通信,自己的OSS服务器可以隔离不同团队(不同的团队申请不同的Bucket),而且不同每次重新配置docker服务,只需要apply一下plugin,然后改一下配置即可,非常方便

本篇针对第二种方式进行讲解,第一种方式可以参考以下一些文章的相关部分
Build Cache Node User Manual | Gradle Enterprise Docs
使用本地和远程的Gradle构建缓存加快构建速度
Android-Studio编译速度优化
Using Gradle Build Cache Server

谷歌 androidx团队开源了一个GitHub - androidx/gcp-gradle-build-cache,就是利用Google Cloud Storage来实现这个需求的

但是国内最大的OSS服务商还是阿里云,这个插件不支持,于是我仿照它的实现写了一个基于阿里云OSS的插件GitHub - neas-neas/aliyun-gradle-build-cache,用法类似

下面我们就从这个插件的用法展开,详细讲解如何创建一个阿里云OSS Bucket,如何配置gradle文件,后面再简单测试一下效果讲起
再分析其实现具体实现过程,你也可以基于自己公司的OSS服务实现一个自己的build cache server

阿里云OSS有一定的免费额度,超过额度会收费,你可以在简单的项目里面测试

使用方法

1. 创建阿里云OSS Bucket

首先去阿里云OSS官网创建OSS Bucket oss.console.aliyun

学新通

点击立即创建开始创建Bucket,顺便记录一下endpointbucket name,没有记下来也没关系,后面可以在概览里面找到

学新通

然后在bucket页面找到权限控制 -> RAM访问控制,前往RAM控制台

学新通

如果没有用户要先创建用户,至少勾选OpenAPI调用访问

学新通

创建用户成功后会跳转到这个页面,这里需要记录下AccessKey IDAccessKey Secret,后面关闭页面就获取不到了

学新通

用户创建完后,给用户添加权限

学新通

权限选中OSS相关的,保险起见FullAccessReadOnlyAccess都选上了,因为我之前都配置过了所以显示是灰色的

学新通

至此阿里云OSS的Bucket就创建完成了,现在就可以去项目中进行相关的配置

2. 配置gradle

settings.gradle中添加如下配置,强调一下是settings,kts脚本类似这里就不列出来了

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'io.github.neas-neas:alibuildcache:1.0.0'
    }
}
apply plugin: 'io.github.neas-neas.alibuildcache'

import io.github.neas.AliyunBuildCache
import io.github.neas.AliyunBuildCacheServiceFactory
import io.github.neas.ExportedAliyunCredentials

buildCache {
	registerBuildCacheService(AliyunBuildCache, AliyunBuildCacheServiceFactory)
    remote(AliyunBuildCache) {
        endpoint = 'your-aliyun-oss-endpoint'
        bucketName = "bucket-name"
        credentials = new ExportedAliyunCredentials("your-access-key-id", "your-secret-key")
        push = true //System.getenv().containsKey("CI")
    }
}

新方式引入插件如下,这种方式要上传到gradle plugin portal,文章发布时还没有审核完毕(太慢了他们),等审核完才能使用,目前只能使用上面那种旧方式

plugins {
    id("io.github.neas-neas.alibuildcache") version "1.0.0"
}

然后之前在创建Bucket时记录的信息这里就需要用上了

endpoint
bucketName
accessKeyId
secretKey

和我们记录时的参数名字一样,不需要过多解释了,对座入号填入即可

照官方推荐push只在CI机器上开,developer的机器拉缓存就行,不过为了测试我们这里先改为true好了

3. 测试效果

所有都配置好了,我们来测试一下看看情况

rm -r ~/.gradle/caches/build-cache-1
./gradlew clean build -i

rm删除掉本地build cache缓存,因为我们要看remote cache,本地缓存优先级更高,所以要排除它 -i 可以在输出中看到相关日志

第一次执行,看看compileJava输出

学新通

因为没有缓存,所以第一次执行会store到阿里云OSS

再执行一下上面的命令,再看看compileJava的输出

学新通

因为没有本地缓存(被我们提前rm了,不rm的话第一步执行时也会在本地进行保存的),我们可以看到compileJava task被标记为了FROM_CACHE,2次的cache key完全一致,而且日志输出了是从阿里云OSS下载下来的

有这个key,我们也可以去阿里云OSS Bucket文件管理页面找到对应的文件,将它下载下来看看它到底是什么

学新通

其实它就是个tar包压缩文件,可以进行解压看看里面到底有什么,这个RemoteBuildCache就是我测试项目里面的代码文件了,你也可以对你的class文件反编译看看是否一致。这部分在Gradle深入解析 - Task原理(执行篇)其实有讲过了

此外针对android项目建议同时使用上GitHub - gradle/android-cache-fix-gradle-plugin: Gradle plugin that fixes Android build caching problems,agp插件对cache的实现有些问题,这个插件可以规避一些此类的问题

具体实现

关系图示意如下

学新通

核心方法

BuildCacheService

最主要的是实现BuildCacheService这个接口,接口有2个非常关键的方法loadstore

public interface BuildCacheService extends Closeable {  
    boolean load(BuildCacheKey key, BuildCacheEntryReader reader) throws BuildCacheException;  
  
	void store(BuildCacheKey key, BuildCacheEntryWriter writer) throws BuildCacheException;  
  
    void close() throws IOException;  
}

load就是拿key去请求OSS获取文件,然后将获取到的InputStream对接给reader
store就是将文件保存到OSS,调用writerwriteTo方法将数据导入到我们的OutputStream,再将OutputStream转为InputStream传给OSS服务器
阿里云OSS有提供SDK,按照其SDK文档就行对应方法调用即可

BuildCache

public interface BuildCache {  
  
    boolean isEnabled();  
  
    void setEnabled(boolean enabled);  
  
    boolean isPush();  
  
    void setPush(boolean enabled);  
}

BuildCache是用于配置BuildCacheService的,类似于写gradle plugin时的extension
默认有enabledpush2个参数
对于OSS来说还不够,以阿里云为例,还需要endpointbucketNamecredentials(主要用于配置accessKeyIdsecretAccessKey)

我们可以通过继承来实现自己的BuildCache类,比如

abstract class AliyunBuildCache(  
) : AbstractBuildCache() {  
    lateinit var endpoint: String  
  
    var credentials: AliyunCredentials = DefaultAliyunCredentials  
}

BuildCacheServiceFactory

public interface BuildCacheServiceFactory<T extends BuildCache> {
	BuildCacheService createBuildCacheService(T configuration, Describer describer);
}

这个接口是用来创建BuildCacheService,看看AliyunBuildCacheServiceFactory的实现,调用describer结合buildCache进行一些描述性质的配置,然后用buildCache去创建AliyunBuildCacheService实例 ![[aliyun-gradle-plugin-factory.png]]

Describer

interface Describer {     
     Describer type(String type);   
     
     Describer config(String name, String value);  
}

用于描述BuildCacheService
type 网络请求的是http,本地的是directory,自定义的比如我这里是aliyun
config 配置一些tag,例如bucketName的值,endpoint
这些信息可以被build scan插件收集,对于判断缓存命中率有一定帮助

建立关联

需要在Plugin里面去绑定关系

class AliyunGradleBuildCachePlugin : Plugin<Settings> {  
    override fun apply(settings: Settings) {  
        settings.buildCache.registerBuildCacheService(  
            AliyunBuildCache::class.java,  
            AliyunBuildCacheServiceFactory::class.java  
        )  
    }  
}

注意这是一个针对Setting的Plugin,调用registerBuildCacheService注册BuildCacheBuildCacheServiceFactory

之后就可以在settings.gradle脚本对BuildCache进行配置了,例如上面提到过的

buildCache {  
    remote(AliyunBuildCache) {  
        endpoint = 'your-end-point'  
        bucketName = "bucket-name"  
        credentials = new ExportedAliyunCredentials("your-access-key-id", "your-secret-key")  
        push = true
    }  
}

至此关于Build Cache的使用和原理大致都进行了说明,Build Cache在实际使用中如果感觉效果不佳,那还需要从多个方面去提升它的缓存命中率,有几个对其命中率有影响的因素,例如执行gradle的JVM的版本不同,Java/Kotlin编译时的JVM版本不同,classpath变更等,可能需要通过build scan等构建信息收集方式去进行具体分析,以提升缓存命中率。关于构建信息的收集可以参考我之前的如何像build scan一样收集gradle构建信息

参考资料

GitHub - androidx/gcp-gradle-build-cache
Docker
使用本地和远程的Gradle构建缓存加快构建速度
Android-Studio编译速度优化
Using Gradle Build Cache Server. Fastest way to work is to avoid doing… | by César Ferreira | Medium
Build Cache Node User Manual | Gradle Enterprise Docs
GitHub - rnett/github-actions-gradle-cache

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfgjjeg
系列文章
更多 icon
同类精品
更多 icon
继续加载