调试远程缓存命中以进行远程执行

报告问题 查看源代码

本页面介绍了如何检查缓存命中率,以及如何在远程执行环境中调查缓存未命中。

本页面假定您的构建和/或测试可以成功利用远程执行,并且您希望确保有效利用远程缓存。

检查缓存命中率

在 Bazel 运行的标准输出中,查看列出进程的 INFO 行,这些进程大致对应于 Bazel 操作。该行会详细说明执行操作的位置请查找 remote 标签(表示远程执行的操作)、linux-sandbox(表示在本地沙盒中执行的操作)以及其他执行策略的其他值。结果来自远程缓存的操作显示为 remote cache hit

例如:

INFO: 11 processes: 6 remote cache hit, 3 internal, 2 remote.

在此示例中,有 6 次远程缓存命中,2 项操作没有缓存命中,而是远程执行。这 3 个内部部分可以忽略。它通常是微小的内部操作,如创建符号链接。此摘要中不包含本地缓存命中。如果发现 0 个进程(或数字小于预期),请运行 bazel clean,后跟构建/测试命令。

对缓存命中进行问题排查

如果您没有获得预期的缓存命中率,请执行以下操作:

确保重新运行相同的构建/测试命令会生成缓存命中

  1. 运行您希望填充缓存的构建和/或测试。首次在特定堆栈上运行新构建时,您应该不会遇到远程缓存命中。在远程执行过程中,操作结果会存储在缓存中,后续运行应该会获取这些结果。

  2. 运行 bazel clean。此命令会清理本地缓存,这样您可以调查远程缓存命中,而不会使结果被本地缓存命中遮盖。

  3. (在同一机器上)再次运行您要调查的构建和测试。

  4. 查看 INFO 行,了解缓存命中率。如果您只看到 remote cache hitinternal 以外的进程,则表示系统正确填充和访问您的缓存。在这种情况下,请跳至下一部分。

  5. 造成差异的原因可能是 build 中的非封闭性问题,导致操作在两次运行中收到不同的操作键。如需查找这些操作,请执行以下操作:

    a. 重新运行相关构建或测试以获取执行日志:

      bazel clean
      bazel --optional-flags build //your:target --execution_log_binary_file=/tmp/exec1.log
    

    b. 比较两次运行之间的执行日志。确保这两个日志文件中的操作相同。 差异可让您了解运行之间发生的更改。请更新 build 以消除这些差异。

    如果您能够解决缓存问题,并且现在重复运行会生成所有缓存命中,请跳至下一部分。

    如果您的操作 ID 相同,但没有缓存命中,则表明您的配置中的某些内容阻止了缓存。请继续阅读本部分以检查常见问题。

  6. 检查执行日志中的所有操作是否都将 cacheable 设置为 true。如果指定操作的执行日志中没有 cacheable,则意味着相应规则在 BUILD 文件中的定义中可能包含 no-cache 标记。查看执行日志中的 mnemonictarget_label 字段,以帮助确定操作的来源。

  7. 如果操作相同且为 cacheable,但没有缓存命中,可能是因为您的命令行包含 --noremote_accept_cached,这会停用对 build 的缓存查找。

    如果难以确定实际命令行,请使用 Build Event Protocol 中的规范命令行,如下所示:

    a. 将 --build_event_text_file=/tmp/bep.txt 添加到 Bazel 命令中,以获取日志的文本版本。

    b. 打开文本版本的日志,然后使用 command_line_label: "canonical" 搜索 structured_command_line 消息。展开后,系统会列出所有选项。

    c. 搜索 remote_accept_cached 并检查它是否已设置为 false

    d. 如果 remote_accept_cachedfalse,请确定是在命令行中还是在 bazelrc 文件中将其设置为 false

确保跨机器缓存

在同一机器上按预期发生缓存命中后,在其他机器上运行相同的构建/测试。如果您怀疑多台机器之间未发生缓存,请执行以下操作:

  1. 对构建稍作修改,以避免命中现有缓存。

  2. 在第一台机器上运行 build:

     bazel clean
     bazel ... build ... --execution_log_binary_file=/tmp/exec1.log
    
  3. 在第二台机器上运行 build,确保包含第 1 步中所做的修改:

     bazel clean
     bazel ... build ... --execution_log_binary_file=/tmp/exec2.log
    
  4. 比较两次运行的执行日志。如果日志不完全相同,请检查 build 配置是否存在差异以及主机环境中泄露到任一 build 的属性。

比较执行日志

执行日志包含在构建期间执行的所有操作的记录。每个操作都有一个 SpawnExec 元素,其中包含操作键中的所有信息。因此,如果日志相同,则操作缓存键也相同。

如需比较未按预期共享缓存命中的两个构建的日志,请执行以下操作:

  1. 从每个 build 获取执行日志,并将其存储为 /tmp/exec1.log/tmp/exec2.log

  2. 下载 Bazel 源代码,然后使用以下命令导航到 Bazel 文件夹。您需要源代码才能使用 execlog 解析器解析执行日志。

    git clone https://github.com/bazelbuild/bazel.git
    cd bazel
    
  3. 使用执行日志解析器将日志转换为文本。以下调用还会对第二个日志中的操作进行排序,以便与第一个日志中的操作顺序相匹配,以便于比较。

    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
    
  4. 使用您喜爱的文本差异 /tmp/exec1.log.txt/tmp/exec2.log.txt