前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >2023-04: 为什么你该试试 Sccache?

2023-04: 为什么你该试试 Sccache?

作者头像
MikeLoveRust
发布2023-02-15 20:44:44
1K0
发布2023-02-15 20:44:44
举报

Sccache[1] 是由 mozilla 团队发起的类 ccache[2] 项目,支持 C/CPP, Rust, nvcc 等语言,并将缓存存储在本地或者云存储后端。在 v0.3.3 版本中,Sccache 加入了原生的 Github Action Cache Service 支持;在后续的 v0.4.0-pre.6[3] 版本中,社区对该功能进行了持续的改进,目前已经初步具备了在生产 CI 中应用的能力。

最近我在 PyO3/maturin[4] 的 CI 中引入了 sccache 做了测试,发现它有如下优势:

  • 部署配置更容易:无需指定 shared-key,不需要操心 GHA 内部的 cache-from/cache-to 逻辑,配置 SCCACHE_GHA_ENABLED: "true" 即可
  • 支持多种语言:sccache 同时支持缓存 C/CPP,Rust,nvcc 多种语言的不同编译器,以 Rust 为例,配置 RUSTC_WRAPPER: "sccache" 即可
  • 大部分场景下更快:sccache 缓存的是编译产物,不需要提前加载全部的缓存,也不需要在构建完成后上传缓存内容
  • 并发任务友好:sccache 能在多个并发执行的 job/workflow 之间共享缓存,不需要等到构建结束
  • 无缓存冲突:sccache 对每个编译产物的输入(参数,环境变量,文件等)进行 hash 计算,能构建一个全局的无冲突缓存,不会出现缓存冲突,不需要额外指定不同的 cache key
  • 无供应商锁定:sccache 基于 opendal[5] 构建,天然支持各种不同的存储服务,在未来的 CI 演进中,可以无缝切换到 s3/gcs/azlob 等服务中,不依赖 GHA Cache 服务
  • 活跃维护中 (图穷匕见):sccache 目前由作者本人活跃贡献中,使用中遇到的问题可以直接提交反馈

以下是在 maturin 项目中的测试结果:

Cases

Sccache vs rust-cache (2nd)

Sccache vs rust-cache (3rd)

Test (ubuntu-latest, 3.7)

59.72%

-1.68%

Test (ubuntu-latest, 3.8)

-4.70%

-8.22%

Test (ubuntu-latest, 3.9)

30.72%

10.81%

Test (ubuntu-latest, 3.10)

1.03%

12.15%

Test (ubuntu-latest, 3.11)

-10.16%

-29.35%

Test (ubuntu-latest, pypy3.8)

18.34%

-3.84%

Test (ubuntu-latest, pypy3.9)

5.13%

22.90%

Test (macos-latest, 3.7)

11.87%

5.65%

Test (macos-latest, 3.8)

-7.82%

-13.65%

Test (macos-latest, 3.9)

-17.98%

-45.20%

Test (macos-latest, 3.10)

-13.20%

-15.38%

Test (macos-latest, 3.11)

-17.44%

-29.55%

Test (macos-latest, pypy3.8)

14.83%

-23.32%

Test (macos-latest, pypy3.9)

-28.03%

-38.56%

Test (windows-latest, 3.7)

30.08%

24.22%

Test (windows-latest, 3.8)

35.11%

41.14%

Test (windows-latest, 3.9)

9.24%

-5.28%

Test (windows-latest, 3.10)

-8.56%

-15.81%

Test (windows-latest, 3.11)

-1.39%

-36.49%

Test (windows-latest, 3.8)

-19.99%

-35.54%

Test (windows-latest, 3.9)

18.95%

-8.55%

表格中对比的是使用 sccache 第二次/第三次运行与使用 rust-cache 时候的差异,加粗的复数条目表示 sccache 比 rust-cache 更快。可以看到,随着 Cache 命中率的提高,sccache 对比 rust-cache 最大能取得将近 50% 的提升。

试试 Sccache 吧,任何不爽的地方请到 issues[6] 反馈,同时欢迎参与贡献~


接下来的部分我会首先介绍 Github Action Cache Service 的内部 API 和它的工作原理,然后对比 rust-cache / sccache 实现的差异来说明为什么 sccache 更好/更快。

Github Action Cache Service 原理

Github Action Cache Service 本质上是一个支持 prefix query 的 immutable 存储服务,它提供了如下非公开的 API:

查询缓存

GET /cache?keys=abc,ab,a&version=v1

  • keys: 指定一组逗号分割的查询 key,返回的结果是相同 version 下前缀匹配的最新 key
  • version:指定 cache key 所使用的 namespace

预留缓存

POST /caches

  • • inputs: {key: <cache_key>, version: <cache_version>}
  • • outputs: {cache_id: <cache_id>}

每一组 (key, version) 被预留之后,后续所有携带相同 key & version 的请求都会返回 already exists 错误,也就是说缓存无法覆盖。请求成功后会返回数字的 cache_id,后续上传缓存和创建缓存都会用到它。

上传缓存

PATCH /caches/[cache_id]

上传具体的缓存内容,使用 Content-Range 来标记本次上传的缓存位置。

创建缓存

POST /caches/[cache_id]

在所有的缓存内容都创建完毕后,可以使用这个 API 来创建缓存。只有在这个 API 响应成功后,缓存才能被查询到。

rust-cache 实现

在这套内部 API(合理怀疑是 Azure DevOps 服务提供的)的基础上,Github 提供了 actions/cache[7] 供用户使用,而 rust-cache[8] 正是基于 @actions/cache 实现的。

rust-cache 会基于 github job_id,rustc 版本,环境变量,Cargo.lock 等信息计算出一个 cache key,然后把 ~/.cargo./target 打包到一起上传。如果 cache 命中就加载到本地并解压缩使用,如果 cache miss,则会在 post action 中将 cache 上传。

rust-cache 的优势是整个过程只会调用一次 GHA Cache 的 API,很少会触发 rate limit,缺点是一旦 cache 没有命中,就需要完全从零构建。

sccache 实现

sccache 的 GHA 实现则是完全基于文件的:

sccache 会根据每一次 rustc 调用时传入的环境变量,二进制,编译参数,输入文件等信息计算一个 hash 作为 cache key,如果文件存在就直接从存储服务中加载,跳过本次编译操作,否则就进行编译并将结果写入到存储服务中。这就意味着:

  • • sccache 不需要处理不同输入带来的缓存冲突,可以使用总是唯一的 hash 作为 cache key
  • • sccache 可以在 rustc 编译时下载需要缓存,不需要提前加载全部的内容,也不需要在 Job 完成后全部上传
  • • sccache 缓存加载逻辑不强依赖于 Cargo.lock 本身,即使在依赖出现大量变化的情况下,也能够重用缓存
  • • sccache 可以在并发的 Job 之间重用缓存,因为大家共享同一个无冲突的存储空间

不仅如此,sccache 还能够应用于 c/cpp 等语言的编译缓存,如果项目中同时还存在 gcc/clang 等编译器的使用,只需要简单配置即可共享缓存。

为了帮助用户更好地在 Github Action 中使用 Sccache,我们开发了 sccache-action[9]。不过我的 PR 目前还没有合并,可以先使用我的 fork:

代码语言:javascript
复制
- name: Sccache Setup
  # Just for test, come back to upstream after released
  uses: Xuanwo/sccache-action@c94e27bef21ab3fb4a5152c8a878c53262b4abb0
  with:
    version: "v0.4.0-pre.6"

接下来只需要配置两个环境变量即可:

代码语言:javascript
复制
env:
    SCCACHE_GHA_ENABLED: "true"
    RUSTC_WRAPPER: "sccache"

在每个 Job 的末尾,sccache-action 会输出本次 Cache 的使用情况:

代码语言:javascript
复制
/opt/hostedtoolcache/sccache/0.4.0-pre.6/x64/sccache --show-stats
Compile requests                   1887
Compile requests executed          1035
Cache hits                          836
Cache hits (C/C++)                   22
Cache hits (Rust)                   814
Cache misses                        189
Cache misses (Rust)                 189
Cache timeouts                        0
Cache read errors                     0
Forced recaches                       0
Cache write errors                    0
Compilation failures                 10
Cache errors                          0
Non-cacheable compilations            0
Non-cacheable calls                 852
Non-compilation calls                 0
Unsupported compiler calls            0
Average cache write               0.051 s
Average compiler                  1.132 s
Average cache read hit            0.000 s
Failed distributed compilations       0

Non-cacheable reasons:
crate-type                          521
-                                   320
unknown source language              11

Cache location                  ghac, name: sccache-v0.4.0-pre.6, prefix: /sccache/

用户可以根据这些信息来调整自己使用 sccache 的策略。

总结

Sccache 以一种全新的方式使用 GHA Cache 来对 Rust 项目进行编译加速,相比于现存的方案有如下优点:

  • • 部署配置更容易
  • • 支持多种语言
  • • 大部分场景下更快
  • • 并发任务友好
  • • 无缓存冲突
  • • 无供应商锁定
  • • 活跃维护中

欢迎大家在自己的项目中尝试和使用 Sccache!

引用链接

[1] Sccache: https://github.com/mozilla/sccache [2] ccache: https://ccache.dev/ [3] v0.4.0-pre.6: https://github.com/mozilla/sccache/releases/tag/v0.4.0-pre.6 [4] PyO3/maturin: https://github.com/PyO3/maturin [5] opendal: https://github.com/datafuselabs/opendal [6] issues: https://github.com/mozilla/sccache/issues [7] actions/cache: https://github.com/actions/cache [8] rust-cache: https://github.com/Swatinem/rust-cache [9] sccache-action: https://github.com/mozilla/sccache-action

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-01-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Rust语言学习交流 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Github Action Cache Service 原理
    • 查询缓存
      • 预留缓存
        • 上传缓存
          • 创建缓存
            • 引用链接
        • rust-cache 实现
        • sccache 实现
        • 总结
        相关产品与服务
        对象存储
        对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档