资讯动态

Bazel 本地执行场景下的远程缓存命中率排查:从命中统计到执行日志对账的完整调试指南

发布时间:2026/9/12 10:58:29 来源:尧图企业网站定制
Bazel 本地执行场景下的远程缓存命中率排查从命中统计到执行日志对账的完整调试指南【免费下载链接】bazela fast, scalable, multi-language and extensible build system项目地址: https://gitcode.com/GitHub_Trending/ba/bazel本指南聚焦一个非常具体的问题当构建与测试在本地执行、但结果写入远程缓存时如何确认远程缓存被有效利用并系统性地排查缓存未命中cache miss。你将掌握如何阅读 Bazel 的进程统计行、如何甄别远程缓存通信故障、如何借助执行日志execution log与execlog工具对账两次构建以及如何让写缓存与读缓存的两次 Bazel 调用真正共享命中。本文以 cache-local.mdx 为骨架结合 cache-remote.mdx、caching.mdx 及仓库内execlog、diskcache工具的源码与说明展开。适用前提本地执行 远程缓存本指南面向以下场景你已有一个能够在本地成功构建的 build 或 test该构建已配置使用远程缓存例如通过--remote_cache或--disk_cache你希望确认远程缓存正在被有效利用而不是每次构建都在本地重跑。需要特别区分的是远程执行remote execution与本地执行local execution走的是两条不同的路径。远程执行会把 action 分发到远端机器构建失败可能直接导致构建整体失败而本地执行即使无法读写远程缓存构建依然可以成功缓存问题只会静默地表现为命中率低于预期。这正是本地执行场景下缓存问题更难发现的原因也是本文需要单独成篇的价值所在。远程执行场景的完整排查流程见 Debugging Remote Cache Hits for Remote Execution其中介绍的方法检查命中率、对比执行日志、跨机器验证等对本地执行同样适用本文在继承这些方法的基础上补充本地执行特有的排查要点。第一步检查缓存命中率成功命中远程缓存的 action 会出现在 Bazel 运行日志的进程统计行status line中。在本地执行 远程缓存场景下典型输出如下INFO: 7 processes: 3 remote cache hit, 4 linux-sandbox.含义解读共 7 个待执行的 action其中 3 个命中了远程缓存显示为remote cache hit结果直接从缓存取回无需本地执行4 个未命中回退到本地执行策略linux-sandbox即在本机沙箱中运行数字7大致对应本次构建中的 action 数量。几点需要特别注意本地缓存命中不计入该统计。如果你上一次构建已经在本地留下产物Bazel 会先复用本地结果这部分不会出现在remote cache hit中。因此若想纯粹地评估远程缓存命中率应先用bazel clean清掉本地缓存再运行。如果统计显示0 processes或数字明显低于预期同样建议执行bazel clean后再跑一次构建/测试命令排除本地缓存对统计的干扰。远程执行场景的统计行格式与之类似例如INFO: 11 processes: 6 remote cache hit, 3 internal, 2 remote.其中remote表示 action 在远端执行、internal表示创建符号链接之类的微小内部 action可忽略。不要用 action 的 stdout/stderr 来估算命中率。远程缓存会额外存储每个 action 的 stdout 与 stderr见 caching.mdx因此某条日志被打印出来不代表该 action 真的被重新执行过。第二步确保与远程缓存端点的通信成功本地执行下无法与远程缓存通信不会导致构建失败这是与远程执行最关键的差异。因此排查的第一件事就是检查 Bazel 输出中是否有如下警告WARNING: Error reading from the remote cache:或WARNING: Error writing to the remote cache:这类警告之后通常会紧跟具体的连接错误信息例如远程缓存端点地址拼写错误mistyped endpoint name凭据配置错误incorrectly set credentials网络不通或代理配置问题。定位到错误后逐一修复即可。如果错误信息不够详细可追加--verbose_failures标志让 Bazel 输出更完整的失败细节。本地执行 vs 远程执行失败模式的差异在远程执行中如果 Bazel 无法与远端端点通信构建会直接失败——因为 action 必须被分发到远端才能执行而在本地执行中action 本来就要在本机运行缓存只是锦上添花因此失败被降级为警告。理解这一点后排查时就要主动在输出中搜索警告而不是等到构建失败才意识到缓存可能有问题。第三步参照远程执行的通用排障清单在确认通信正常后如果命中率仍然低于预期需要按 cache-remote.mdx 中的步骤系统排查3.1 在同一台机器上复现命中运行你期望填充缓存的构建/测试命令。第一次在全新机器栈上运行通常不会有远程缓存命中这是正常现象执行bazel clean清除本地缓存避免本地命中掩盖远程命中的真实情况再次运行相同的构建/测试命令检查INFO行。如果除remote cache hit和internal外再无其他进程说明缓存已被正确填充并被访问若两次运行的 action key 不一致大概率是构建中存在非密闭non-hermetic因素。此时进入第 3.2 节通过执行日志定位差异。3.2 用执行日志定位非密闭因素生成两次运行的执行日志bazel clean bazel var--optional-flags/var build //varyour:target/var --execution_log_compact_file/tmp/exec1.log然后对比两次运行的日志对比方法见下文对比执行日志一节。确保两个日志文件中的 action 完全一致任何差异都提示了两次运行之间发生了什么变化据此修正构建配置。3.3 检查 action 是否可缓存如果两次运行的 action ID 完全一致却依然没有命中可能是配置层面阻止了缓存。先检查执行日志中每个 action 的cacheable字段是否都为true若某 action 的日志中不包含cacheable说明对应规则可能在BUILD文件中带有no-cachetag可通过日志中的mnemonic和target_label字段定位该 action 来源于哪个规则。3.4 检查缓存读取是否被显式关闭如果 action 完全一致且cacheable为 true 却仍无命中检查命令行中是否包含--noremote_accept_cached——该标志会为本次构建禁用缓存查找。如果难以确认实际生效的命令行可以使用 Build Event Protocol 获取规范化命令行canonical command line在 Bazel 命令中追加--build_event_text_file/tmp/bep.txt生成文本格式的 BEP 日志打开该日志搜索structured_command_line消息其中command_line_label: canonical对应的消息会列出展开后的全部选项在其中搜索remote_accept_cached确认其是否被设置为false若为false进一步确定它是在命令行还是 bazelrc 配置文件中被设置的。第四步让读缓存的 Bazel 调用也能命中很多团队采用CI 写缓存、开发者读缓存的分工模式。这类只读缓存的 Bazel 调用与写缓存的调用往往有着不同的命令行配置因此需要额外确认以下几点确保--remote_cache标志已设置且输出中没有相关警告见第二步确保读缓存的调用构建的目标与写缓存的调用一致——目标不一致自然谈不上共享命中按照 确保跨机器缓存 的步骤验证从写缓存机器到读缓存机器的缓存共享是否成立。跨机器验证步骤对构建做一个小改动避免命中已有缓存在第一台机器上运行bazel clean bazel ... build ... --execution_log_compact_file/tmp/exec1.log在第二台机器上运行确保包含第 1 步的改动bazel clean bazel ... build ... --execution_log_compact_file/tmp/exec2.log对比两份执行日志。若日志不一致排查两台机器的构建配置差异以及宿主机环境属性如$PATH、环境变量是否泄漏进了构建。第五步对比执行日志定位缓存未命中的根源执行日志是排查缓存问题最有力的工具。每条记录描述了一个 action 的输入不仅是文件还包括命令行参数、环境变量等与输出因此通过检查日志可以揭示某 action 为何被重新执行。执行日志的三种格式执行日志可通过以下三个标志之一生成格式互通标志格式说明--execution_log_compact_filecompact紧凑官方推荐文件体积小、运行时开销极低--execution_log_binary_filebinary二进制与 compact 同源的二进制编码--execution_log_json_fileJSON便于其他工具直接消费三种格式之间可以通过//src/tools/execlog:converter工具互相转换详见 execlog/README.md例如二进制转 JSONbazel build //src/tools/execlog:converter bazel-bin/src/tools/execlog/converter \ --input binary:/tmp/binary.log --output json:/tmp/json.log用 execlog parser 生成可 diff 的文本对比两份日志例如分别保存为/tmp/exec1.log和/tmp/exec2.log时直接 diff 二进制日志并不现实。仓库自带解析工具//src/tools/execlog:parser定义于 execlog/BUILD主类com.google.devtools.build.execlog.ExecLogParser构建并运行bazel build //src/tools/execlog:parser bazel-bin/src/tools/execlog/parser \ --log_path/tmp/exec1.log \ --log_path/tmp/exec2.log \ --output_path/tmp/exec1.log.txt \ --output_path/tmp/exec2.log.txt该工具会把两份日志都转换为人类可读的文本并将第二份日志中的 action 重新排序以匹配第一份的顺序依据首个输出文件是否相同进行匹配未匹配的 action 排到末尾使 diff 更有意义。之后用你习惯的文本 diff 工具对比/tmp/exec1.log.txt与/tmp/exec2.log.txt即可。其他实用选项见 execlog/README.md--restrict_to_runnerlinux-sandbox只输出在指定执行策略下运行的 action便于聚焦排查处理超大日志时可加大 JVM 堆如--jvm_flag-Xmx4g注意由于 Bazel 本身具有不确定性不同次运行产生的日志中 action 顺序可能不同重排序便于 diff但也可能打乱第二份日志的逻辑顺序。本地执行场景的典型非密闭因素对比日志时以下因素经常导致 action key 变化或缓存污染需要重点检查环境变量泄漏进 actionaction 定义中包含环境变量不同机器$PATH不同就可能导致无法共享命中。只有通过--action_env显式白名单化的环境变量才会进入 action 定义见 caching.mdx。如果命中率异常偏低检查环境中是否存在旧的/etc/bazel.bazelrcBazel 的 Debian/Ubuntu 包曾通过它注入包含$PATH的白名单工作区外的工具未被追踪Bazel 不追踪工作区之外的工具例如使用/usr/bin/下的编译器时两台机器编译器版本不同会产生相同 action hash 但不同输出造成错误的命中反过来也会掩盖真实差异构建期间输入文件被修改可能向缓存上传无效结果可启用--experimental_guard_against_concurrent_changes进行变更检测一般情况下应避免在构建过程中修改源文件。辅助手段磁盘缓存及其垃圾回收除了网络远程缓存Bazel 还支持把文件系统目录当作缓存--disk_cache适用于切换分支、同一项目的多个 checkout 等场景。它在排查本地执行缓存问题时也非常有用——你可以把磁盘缓存当作本地可检视的远程缓存来观察命中行为build --disk_cachevarpath/to/build/cache/var相关要点不带路径运行时使用默认位置outputUserRoot/cache/disk与 repository cache 同级输出用户根目录见 user-manualbuild --nodisk_cache可显式禁用路径支持~别名替换为当前用户主目录便于在项目提交的.bazelrc中为所有开发者统一开启从 Bazel 7.4 起可用--experimental_disk_cache_gc_max_size与--experimental_disk_cache_gc_max_age限制缓存总大小或单个条目存活时长Bazel 会在构建空闲期自动执行垃圾回收空闲等待时长由--experimental_disk_cache_gc_idle_delay控制默认 5 分钟需要按需手动回收时可使用仓库自带的独立工具见 diskcache/README.mdbazel run //src/tools/diskcache:gc -- \ --disk_cache/path/to/disk/cache \ --max_age7d --max_size2G--max_age与--max_size至少需指定一个。缓存机制背景命中背后的两个存储理解命中率之前有必要了解远程缓存的数据组织方式详见 caching.mdx。Bazel 把构建拆分为离散的action每个 action 显式声明输入、输出文件名、命令行与环境变量。远程缓存存储两类数据action cacheaction 哈希到 action 结果元数据的映射内容寻址存储CAS输出文件本身。HTTP 缓存协议下action 结果元数据存放在/ac/路径下输出文件存放在/cas/路径下Blob 通过 PUT 上传、GET 下载HTTPS、grpc、grpcs协议同样受支持。一条命中意味着某个 action 的输入哈希能在 action cache 中查到结果且对应的输出文件已在 CAS 中可获取——任何输入文件、命令行、环境变量的变化都会改变 action 哈希从而错过命中。这正是本文所有排查手段围绕的核心模型。总结一份可照做的排查清单步骤检查项关键命令/标志1查看进程统计行确认remote cache hit数量观察INFO: N processes: ...行2确认与远端通信成功搜索WARNING: Error reading/writing to the remote cache必要时加--verbose_failures3同一机器复现命中bazel clean后重跑4检查 action 是否可缓存执行日志中的cacheable、mnemonic、target_label5确认未被--noremote_accept_cached关闭--build_event_text_file/tmp/bep.txt 查找structured_command_line中remote_accept_cached6让读缓存调用可命中确认--remote_cache、相同 targets、跨机器日志一致7对比执行日志定位差异--execution_log_compact_file//src/tools/execlog:parser按照上述顺序排查绝大多数本地执行 远程缓存命中率低的问题都能被定位到具体环节是端点配置错误、非密闭输入导致的 action key 漂移还是规则被标记为不可缓存。最后记得本地缓存命中不计入统计评估远程命中率前先bazel clean。【免费下载链接】bazela fast, scalable, multi-language and extensible build system项目地址: https://gitcode.com/GitHub_Trending/ba/bazel创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价