GitHub Actions cache 三个真实坑:restore-keys 软匹配、容量上限、lookup-only 陷阱

GitHub Actions cache 陷阱

问题现象

GitHub Actions 跑了三个月,cache 命中率始终在 30% 徘徊。明明每次只改了一行代码,却每次都重新下载 400MB 的 node_modules。直到加了 restore-keys,命中率也没见涨。

restore-keys 的软匹配陷阱

actions/cache 有两层匹配:精确 key 优先,MISS 后才轮到 restore-keys 做前缀匹配。但前缀匹配的逻辑和直觉相反。

陷阱一:软匹配可能加载错误版本。Django 3.2→4.2 升级后 requirements.txt hash 变了,精确 key MISS。restore-keys: {{ runner.os }}-pip- 匹配到旧缓存,restore 成功但包版本不对。后续 pip install 报错:

ERROR: Cannot install django-3.2.0 because you have django 4.2.0

表面 cache 命中率 100%,实际恢复了一个无法使用的缓存。

陷阱二:restore-keys 写法错误等于无效。有人这样写:

restore-keys: |
  {{ runner.os }}-node-{{ hashFiles('**/package-lock.json') }}
  {{ runner.os }}-node-

第一行是完整 hash 前缀,只精确匹配 hash 相同的 key;第二行才是软匹配前缀。真正的软匹配只有第三行(如果 cache 里没有匹配的 hash,就彻底 MISS)。

陷阱三:lookup-only 调试后忘记关掉。有人在调试时加了 lookup-only: true 验证 key 正确,后来删了但没验证 workflow 重新跑出 100% MISS——因为 lookup-only 时根本没写 cache。

容量上限:10GB 之后的 LRU 淘汰

GitHub 每个仓库免费 10GB cache 配额。超过后按 LRU 淘汰。某团队 cache 列表里有 47 个 entry,总大小 9.8GB,某次 pipeline 多创建了几个 cache 后,最老的缓存被静默删掉。

表面 key 命名正确、日志显示 restore 成功、实际解压后目录是空的——因为原来的 cache 已经被 GC 删了。

验证方法:

gh cache list --sort last_accessed_at --limit 10

Created atLast accessed at,确认 cache 是否还存在。长时间没访问的 cache 随时可能被清理。

验证命令

lookup-only: true dry run,不污染现有 cache 就能确认 key 能否命中:

- uses: actions/cache@v4
  with:
    path: ~/.cache/pip
    key: {{ runner.os }}-pip-{{ hashFiles('**/requirements.txt') }}
    restore-keys: |
      {{ runner.os }}-pip-
    lookup-only: true

运行时日志会输出:

Cache not found for key: Linux-pip-abc123...
Cache not found for restore-keys: Linux-pip-

哪个命中了,哪个没命中,一目了然。

现在你可以做什么

第一步:加 lookup-only: true dry run 一次,确认 key 命中情况:

- uses: actions/cache@v4
  with:
    path: ~/.cache/pip
    key: {{ runner.os }}-pip-{{ hashFiles('**/requirements.txt') }}
    restore-keys: |
      {{ runner.os }}-pip-
    lookup-only: true

第二步:删掉 restore-keys 里的完整 hash 前缀行,只保留裸前缀:

restore-keys: |
  {{ runner.os }}-pip-

第三步:跑 gh cache list 确认 cache 是否存在、容量是否快满:

gh cache list --sort last_accessed_at --limit 20

第四步:清理长期不用的 cache,保持配额健康(超过 10GB 后所有 key 都可能被 LRU 随机淘汰):

gh cache delete <cache-id>

Cache 是 CI 速度的关键,但 restore-keys 机制藏着三把刀:软匹配可能加载错误版本、写法错误导致无效、lookup-only 调试后忘记关掉。记住这个顺序:lookup-only 验证 → 确认 key 正确 → 删掉 lookup-only 正式跑。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享