在 CI 上缓存的常用方法是将文件存储到存档,然后将其推送到某个存储,稍后下载并解压缩。很简单。
考虑来自https://github.com/actions/cache的示例
- name: Cache multiple paths
uses: actions/cache@v2
with:
path: |
~/cache
!~/cache/exclude
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
这个片段声明了什么?它说:“请尝试恢复我的缓存,不包括其中一些给出类似名称的缓存ubuntu-abfacada123456
,然后执行其他操作,并以相同的名称返回作业存储缓存的末尾”。
我们也能够提供
restore-keys: ${{ runner.os }}-*
当找不到完全匹配时,获取与模式对应的最新可用缓存key
。
由于其简单明了,这是最广泛的缓存方法之一。
介绍一下我的问题。我有一个有很多依赖项的大型 C++ 项目。它是分几个阶段构建的,还有很多事情需要做得更快。
简而言之,构建包括:
- 准备docker镜像
- 构建由 vcpkg 管理的依赖项
- 使用 ccache 使用 cmake 构建项目
- 运行测试
有3个点可以缓存
- 泊坞窗图像层;大约 1.4Gb,?? 拉链
- vcpkg 下载、构建数据、安装 build-root;约 5Gb,1.4Gb 压缩
- 项目的ccache;高达 8Gb,2Gb 压缩
我已经尝试在 GitLab CI 和 GitHub Actions 上使用常规和常用的缓存技术。对于如此大量的数据,它们的效率不够高。默认缓存存储经常溢出并且较旧但仍然实际的档案被删除。
CI 假设多个 pull/merge 请求、提交、分支的多个构建;计划运行和手动运行。因此总缓存大小超过了通常的报价。
问题
- 存储几乎相同的文件需要太多的存储空间。构建与构建之间的差异小于缓存大小的 5%,通常高达 1%
- 归档 5Gb 的构建数据然后将其从构建机器上传到远程持久存储需要太多时间
- 带有缓存存档的存储比数据过时更频繁
- 一个全新的初始化干净构建机器仍然需要下载完整的缓存,但下载和解包时间总是比存档和上传少得多。
例如,我的 5Gb vcpkg build_dir 在 1 分钟 40 秒内下载和上传,但存档和上传需要 4 分钟 45 秒。我们很少更改vcpkg,通常没有更改上传。
所以任务是减少网络上的流量。
解决方法
我想使用一些备份/恢复实用程序,例如rclone
或restic
存储差异数据。
工作流程几乎相同:
- 下载缓存;
- 做事,即构建/重建,假设这一步也自动检测要重建的内容;
- 上传更新的缓存,只有区别;
- 使用标签标记上传的快照以供将来使用:日期、分支名称、内部版本号等。
关键问题是检测要下载哪个快照。
让我们考虑下一个用例。给定一个从 branch-A 到 branch-main 的 PR。Branch-A 仍在建设中,开发人员经常推动。PR 的每个下一个版本都应该使用前一个版本的缓存。PR 的第一次构建是指基础分支的缓存。
这是问题