大数跨境

如何使用 Go 的缓存缩短 CI 构建时间

如何使用 Go 的缓存缩短 CI 构建时间 索引目录
2025-02-12
0

我们的 CI 管道的集成测试运行缓慢。主要瓶颈不是测试本身,而是编译源代码所需的时间。为了解决这个问题,我们利用 GitHub Actions 的缓存功能来保存和重用 Go 构建缓存,从而大大缩短了 CI 执行时间。

这篇文章介绍了优化 GitHub Actions 工作流程的过程、面临的挑战以及缓存构建工件时遇到的操作障碍。此外,我们将把这些发现推广到大型构建管道及其对 CI/CD 性能的影响。

问题

大多数现代软件项目的 CI/CD 构建时间较长,原因是:

  • 依赖项频繁发生变化,导致缓存的构建无效。

  • 集成测试需要完全重建,涉及代码库的大部分内容。

  • 低效的缓存保留策略,导致不必要的存储膨胀。

  • 依赖隔离不佳,导致级联构建无效。

这些低效率导致 CI 管道变得缓慢,特别是在单一存储库或大型项目中,构建性能直接影响开发速度

将 Go 的构建缓存存储在 GitHub Actions 中

工作流程

典型的测试工作流程包括:

  1. 将 Go 构建缓存从 GitHub Actions 恢复到运行器中。

  2. 运行测试,重用缓存的构建,同时为修改后的代码生成新的缓存。

  3. 将更新的构建缓存存储回 GitHub Actions。

对于使用 Docker 的工作流程,需要执行其他步骤:

  1. 将构建缓存从 GitHub Actions 加载到运行器中。

  2. 将缓存从运行器复制到 Docker 容器。

  3. 在 Docker 容器内运行测试,生成新的构建缓存。

  4. 将更新的缓存从容器复制回运行器。

  5. 保存 GitHub Actions 中的缓存并删除过时的版本。

可视化依赖关系的复杂性

我们的包的依赖图



Go 构建缓存的 GitHub 操作工作流程

- name: Restore Go cache
id: restore-go-cache
uses: actions/cache/restore@v4
with:
path: |
/tmp/.cache
key: test-integration-${{ runner.os }}-go-${{ github.sha }}
restore-keys: |
test-integration-${{ runner.os }}-go-

- name: Copy Go build cache to container
run: |
mkdir -p /tmp/.cache/go-build
docker exec container_name mkdir -p /root/.cache
docker cp /tmp/.cache container_name:/root
rm -rf /tmp/.cache

- name: Run tests
run: make test-integration

- name: Copy Go build cache from container
run: |
mkdir -p /tmp/.cache/go-build
docker cp container_name:/root/.cache/go-build /tmp/.cache

- name: Save Go cache
id: cache-save
uses: actions/cache/save@v4
with:
path: |
/tmp/.cache
key: test-integration-${{ runner.os }}-go-${{ github.sha }}

- name: Delete older cache
run: |
gh extension install actions/gh-actions-cache
gh actions-cache delete ${{ steps.restore-go-cache.outputs.cache-matched-key }} -B ${{ github.ref }} --confirm || true
env:
GH_TOKEN: ${{ github.token }}

在 GitHub Actions 中管理缓存生命周期

每个分支维护一个单独的构建缓存。由于新缓存不会自动替换旧缓存,因此该过程包括:

  1. 创建一个新的缓存。

  2. 删除过时的缓存以防止存储膨胀。

CI 缓存保留问题



缓存存储问题及解决方案

由于我们的集成测试每次构建都会生成约 1GB 的缓存,因此我们面临 GitHub Actions 的10GB 缓存限制。为了缓解这个问题,我们实施了:

  1. 更大的滑道:通过使用更大的滑道来增加存储可用性。

  2. 跨工作流共享缓存:我们不是为每个工作流设置单独的缓存,而是集中缓存以供重用。

  3. 有条件地清除缓存:当更改使过期的缓存无效时,有选择地删除过期的缓存。

检测构建瓶颈

我们使用了一种简单的计时方法来隔离构建缓慢的问题:

go clean -cache  # Clear cache
date && go test && date # Measure test execution time
date && go test && date # Measure test execution time again

通过比较缓存和非缓存运行中的测试执行时间,我们确定了构建开销。

构建缓慢的症状

  • 尽管只运行了几个测试,但 CI 工作流程所花的时间比预期的要长。

  • 本地和 CI 环境之间的运行时差异显著(本地构建受益于持久缓存)。

结论

通过利用 GitHub Actions 中的 Go 构建缓存,我们将 CI 执行时间缩短了 7 分钟。关键要点:

  • 优化工作流程中的缓存使用情况,以最大限度地减少冗余构建。

  • 主动管理缓存生命周期以避免存储限制。

  • 通过时序分析尽早识别缓慢构建区域。

  • 尽可能重构依赖关系以尽量减少不必要的重建。

这些改进通过加速反馈循环和优化 CI/CD 性能,大大提高了开发人员的工作效率。如果您的 CI 构建速度很慢,优化缓存和依赖项管理可以显著提高速度。


【声明】内容源于网络
0
0
索引目录
索引目录是一家专注于医疗、技术开发、物联网应用等领域的创新型公司。我们致力于为客户提供高质量的服务和解决方案,推动技术与行业发展。
内容 444
粉丝 0
索引目录 索引目录是一家专注于医疗、技术开发、物联网应用等领域的创新型公司。我们致力于为客户提供高质量的服务和解决方案,推动技术与行业发展。
总阅读544
粉丝0
内容444