Bazel构建频繁从头执行忽略缓存,如何排查缓存失效原因?
排查Bazel缓存失效的方法
用cquery分析目标依赖与缓存键
- 先获取目标的缓存键:执行
bazel build --remote_upload_local_results=false --nobuild <target>,命令输出里会显示目标的缓存键(格式类似Cache key is: xxx)。 - 对比缓存失效前后的输入依赖:
- 用
bazel cquery <target> --output=starlark --starlark:expr="'\n'.join([str(x) for x in target.files.to_list()])"列出目标的所有输入文件,检查是否存在未预期的文件变更。 - 用
bazel cquery <target> --output=starlark --starlark:expr="'\n'.join([x.label for x in deps(target)])"拉取目标的完整依赖链,排查是否有依赖引入了不稳定的输入(比如动态生成的文件)。
- 用
用bazel analyze-profile定位失效点
- 构建时生成性能文件:
bazel build --profile=build.profile <target> - 分析缓存缺失情况:
bazel analyze-profile build.profile,查看输出中的Cache Misses板块,定位频繁失效的目标,再针对性排查这些目标的输入源。
解决缓存失效的实用技巧
- 稳定构建输入:
- 确保
BUILD、.bzl等构建脚本没有动态生成内容,比如不要在脚本里插入随时间变化的变量,这类内容会导致文件哈希值每次构建都变,直接破坏缓存。 - 所有生成文件必须放在
bazel-out目录下,禁止genrule或自定义规则向源码目录写入文件。
- 确保
- 优化远程缓存配置:
- 确认
--remote_cache指向正确的代理服务,同时开启--remote_upload_local_results=true(本地构建后上传缓存)和--remote_download_minimal=true(只拉取必要的缓存产物)。 - 检查远程缓存的存储权限与生命周期,避免缓存条目被意外清理,或代理没有读取缓存的权限。
- 确认
- 固化第三方依赖(如grpc):
- 引入grpc时,用
http_archive或git_repository固定版本号或commit哈希,杜绝每次构建拉取不同代码的情况。 - 可以为grpc相关目标添加
tags = ["remote_cache"]标签,确保其构建产物被优先缓存到远程代理。
- 引入grpc时,用
- 规避不稳定构建属性:
- 禁止在规则中使用
$(shell date)这类随环境变化的变量,所有路径引用必须用$(location),否则会导致缓存键不稳定。 - 检查是否有规则设置了
local = True,这类规则会强制本地构建,无法使用远程缓存,必要时移除该属性。
- 禁止在规则中使用
- 验证缓存有效性:
- 用
bazel build --remote_download_toplevel <target>测试能否拉取缓存产物,若失败,查看日志中的Cache fetch failed类错误信息定位问题。 - 执行
bazel clean --expunge后重新构建,观察未变更目标是否能命中缓存,以此验证缓存策略是否生效。
- 用
内容的提问来源于stack exchange,提问作者Piotr Jachowicz
相关产品推荐
相关产品推荐

