6

如何为 Rust 项目配置 GitHub Action cache

 1 year ago
source link: https://liujiacai.net/blog/2022/10/29/github-action-cache-for-rust/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

如何为 Rust 项目配置 GitHub Action cache

2022-10-29约 975 字 预计阅读 2 分钟

为了加速 CI 的执行,缓存是非常有效的手段。保证缓存的最高利用率,是使用缓存时最需要关注的点。比如在把整个 target 目录缓存后,何时更新这个缓存?最好的方式是在有依赖变更时,对于 Rust 来说就是 Cargo.lock 有变化,对于 Node 来说就是 package.lock 有变化。

下面我们看看如何利用 cache 这个组件来实现上述效果,主要有三个的参数:

  • key 缓存 ID,可以把整个缓存空间看出是一个 KV 对
  • path 即缓存哪些路径
  • restore-keys 这里指定了当 key 没有命中时,可以选择的缓存

下面用缓存 Rust 项目作为示例进行讲解:

jobs:
  test:
    timeout-minutes: 20
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
      - name: Cache Crates
        uses: actions/cache@v3
        with:
          path: |
            ./target
            ~/.cargo            
          key: debug-${{ runner.os }}-${{ hashFiles('rust-toolchain.toml') }}-${{ hashFiles('Cargo.lock') }}
          restore-keys: |
            debug-${{ runner.os }}-${{ hashFiles('rust-toolchain.toml') }}-
            debug-${{ runner.os }}-            
      - run: cargo test

首先看 key 的定义,分为四个部分,分别是:

  1. 固定值, debug 为了与 release 编译区分开
  2. 变量,操作系统
  3. toolchain 文件 Hash
  4. Cargo.lock 文件 Hash

对于一个 cache 来说,当使用 key 命中时,称为 cache hit ,这时在 Actions 结束时,不需要更新 cache。因此设计这个 key 时,需要注意两点:

  1. key 要能够表示缓存变更,上面四个变量即可以确定一个完整有效缓存
  2. 能够表示缓存变更的字段可能有多个,经常变动的需要放在最后面,上面四个变量就遵循了这个顺序

第二点的设计需要与 restore-key 一起来看。当 Actions 执行时,如果 key 没有不一致,这是说明缓存内容有变,可能是 lock 文件变了,也可能是 toolchain,按照 cache 一般设计来说,key 不一致,是没法使用缓存的。

但这时缓存还是可以用的,比如项目中有 10 个依赖,只是对其中一个做了升级,那么其余 9 个的缓存还是有效的,这时缓存的选取就用到 restore-key 了:

restore-key 指定一系列候选的缓存 key,用作没有命中 key 时的候补缓存

由于候补缓存的方式是从上到下,所以 restore-key 的长度一般都是依次递减。对上面的例子来说,缓存选择方式如下:

  • 如果只是 Cargo.lock 变更了,那么就用第一个 restore-key 指向的缓存,因为它的缓存有效率最高
  • 如果 Cargo.lock 与 toolchain 文件都变更了,那么就用第二个,原因同上
  • 如果当前是 release 编译,不管 Cargo.lock、toolchain 文件有无变更,都无法利用缓存,这样可以避免与 debug 的 cache 混淆,导致 cache 过大

只要 key 没有命中,在 Actions 执行结束后,就会去更新缓存,便于下次直接命中。可以看到,通过 restore-key 的巧妙设计,可以保证当前最有效的缓存一直是最“热”的。

为了安全、成本,GitHub 对缓存做了如下几点的限制:

  • 如果缓存是在 main 分支上产生,那么所有 main 分支衍生的其他分支都可以用到;但是,同时由 main 衍生的分支 B1、B2,他们产生的缓存,是不能共享的
  • 对于 7 天没有访问的缓存,会被自动删掉
  • 缓存空间只有 10G,超过会按照访问时间 LRU 淘汰

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK