Kache:让第二个 worktree 复用第一次编译,而不是再烧一遍 CPU 和磁盘
切换分支、开第二个 worktree、在 CI 上重跑同一份依赖,常常会得到相同的结果:编译器再把已经算过的东西算一遍。target/ 或 build directory 一方面占满磁盘,另一方面又因为路径、工作目录和不同 job 而难以共享。缓存工具很多,但真正影响日常体验的不是“有没有命中率”,而是第二个工作树究竟会多出多少数据、miss 时能否说明原因,以及它会不会悄悄改变现有构建。
今天看的是 kunobi-ninja/kache。它是 Rust、C/C++ 与 CUDA 的编译缓存:为每次编译调用按输入内容生成 key,把输出放进本地内容寻址存储,并在支持的文件系统上用 copy-on-write clone 恢复。相同字节只保留一份;同一台机器上同时遇到相同 key 的构建会合并为一次编译。需要跨机器时,再选配 S3-compatible 或 filesystem remote。
按 GitHub repository、README、LICENSE、main 最新提交和 Releases 在 2026-09-20 18:02 Asia/Shanghai 可核验的信息,kunobi-ninja/kache 有 899 stars、49 forks,主要语言为 Rust,license 是 Apache-2.0。仓库创建于 2026-02-15 19:43:57 UTC;main 最新 HEAD 为 a980a3b,最新 push/提交时间为 2026-09-20 09:56:34 UTC,处理 daemon 关闭时 prefetch summary 的完整性与锁释放。最新 GitHub Release 是 v0.26.0,发布于 2026-09-19 17:59:56 UTC。这意味着它仍在快速演进:团队接入应先固定 release,并在自己的真实项目上测量命中率和磁盘行为。
项目概览
| 属性 | 详情 |
|---|---|
| 仓库 | kunobi-ninja/kache |
| 定位 | Rust、C/C++、CUDA 的内容寻址编译缓存 |
| Stars / Forks | 899 / 49 |
| 主要语言 | Rust |
| 许可证 | Apache-2.0 |
| 创建时间 | 2026-02-15 19:43:57 UTC |
| Latest push / main HEAD | 2026-09-20 09:56:34 UTC / a980a3b |
| 最新 Release | v0.26.0,2026-09-19 17:59:56 UTC |
| 远端缓存 | 可选 S3-compatible(含 AWS S3、MinIO、Cloudflare R2)或 filesystem remote |
它解决的是 worktree 的重复劳动
README 里的核心设计很直接:wrapper 会解析 rustc、cc、c++ 或 nvcc 的调用,hash 会影响输出的输入,并规范化机器本地的路径。于是同一 revision 的两个 worktree 能生成相同 key;恢复时不是重新跑 compiler,而是把已缓存的输出放回新目录。
这特别适合 Rust 仓库里并行处理 issue、review 和实验分支的场景。每个 worktree 可以保留自己的 target directory,不必靠共享一个容易互相污染的目录来换速度。Kache 同时记录 hit、miss 与 passthrough;kache why-miss <crate> 能解释某个 unit 为什么没有复用。比起只给一个模糊百分比,这更方便判断是 feature、环境变量、build script 还是编译器参数破坏了缓存。
它也不只包住 Cargo。C 和 C++ 可以通过 compiler-name shims 接进 Make、CMake、autotools 或 Arch PKGBUILD;CUDA 支持单源 nvcc -c 与 -dc。README 对支持范围写得很明确:Rust library 和 build script 已支持;Rust executable 在 Linux/macOS 支持、Windows 默认关闭;不支持或不安全的 invocation 会直接 passthrough,而不是勉强复用错误产物。
先让配置变更可见
最小 Rust 路径是:
cargo install kache
kache init --check # 先预览将写入的 Cargo 配置
kache init
kache init 会设置 Cargo 的 rustc-wrapper;Unix 上还会为 build-script 的 C/C++ 环境配置相应键。README 说明可以用 kache init --no-service 跳过 OS service,也能用 kache doctor 检查安装状态。这样的 preview 很重要:构建缓存通常要碰全局或用户级配置,先检查 diff 比“装完发现所有工程走了 wrapper”更稳妥。
远端共享则不应默认开启。若本地 cache 已证明有效,团队才可以在配置里填写 S3-compatible bucket,或用 filesystem remote 复用 CI volume。远端凭据走标准 AWS environment variable 或 credential chain;因此 bucket 的访问范围、保留时间、构建输出是否可能包含敏感信息,都应当先按团队的供应链策略评审。
它不是替代所有缓存的魔法开关
Kache 的零拷贝体验依赖文件系统能提供 copy-on-write clone;没有这种能力时,空间收益不会相同。README 提到的 Firefox/APFS 测量值得当作方法参考,而不是对每台机器的承诺:真实收益取决于语言、编译器、feature matrix、容器层和远端网络。
同样,缓存正确性优先于命中率。项目虽说明会让 unsafe invocation passthrough,但引入 wrapper 后仍应从一个非发布分支、两三个工作树开始,跑 kache report --last-build,并保留 KACHE_DISABLED=1 作为单次绕过手段。CI 里也建议先用官方 action 接入一个 job,再验证 artifact、编译时间与 remote 权限,而不是一次性迁移所有流水线。
总结
kache 有意思的地方,不是又做了一个“更快的编译缓存”,而是把 worktree 的可复用性当成一等问题:输入内容决定 key,相同输出只存一份,miss 有解释,远端共享是可选层。对于频繁开 Rust 分支、同时混有 C/C++ 或 CUDA 构建、并且已经被重复 cold build 拖慢的团队,先在本机跑一个可预览的 kache init --check,再用第二个 worktree 验证命中,可能比一开始就设计复杂的共享 target 目录更值得。