动态执行

报告问题 查看源代码 每夜 build · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

动态执行是 Bazel 中的一项功能,可让系统在本地和远程执行 使用第一个分支的输出并行启动相同的操作 结束另一个分支。它将远程构建系统的执行能力和/或大型共享缓存与本地执行的低延迟时间相结合,为干净构建和增量构建提供了两全其美之处。

本页介绍了如何启用、调整和调试动态执行。如果您 已设置本地和远程执行,并正在尝试调整 Bazel 以提高性能,本页就是您的理想之选。如果您尚未设置远程执行,请先参阅 Bazel 远程执行概览

启用动态执行?

动态执行模块是 Bazel 的一部分, 因此您必须已经能够从命令行本地和 相同的 Bazel 设置

如需启用动态执行模块,请将 --internal_spawn_scheduler 标志传递给 Bazel。这会添加一个名为 dynamic 的新执行策略。现在,您可以 使用此策略作为您想动态运行的助记符的策略,例如 --strategy=Javac=dynamic。如需了解如何选择要为哪些助记符启用动态执行,请参阅下一部分。

对于任何使用动态策略的助记符,远程执行策略都是 本地策略来自 --dynamic_remote_strategy 标志, --dynamic_local_strategy 标志。通过 --dynamic_local_strategy=worker,sandboxed 用于设置本地 动态执行分支,尝试通过工作器或沙盒化执行 订单。传递 --dynamic_local_strategy=Javac=worker 仅会替换 Javac 助记符的默认值。远程版本的工作方式与此相同。这两个标志可以多次指定。如果某项操作无法在本地执行,则会照常在远程执行,反之亦然。

如果您的远程系统有缓存,--dynamic_local_execution_delay 标志会在远程系统指示缓存命中后,在本地执行中添加毫秒级延迟。这样可以避免在更多缓存命中时运行本地执行 概率。默认值为 1000 毫秒,但应调整为比缓存命中通常所需的时间稍长一些。实际时间取决于远程系统和往返所需时间。通常,该值会 除非有一部分距离用户太远 增加往返延迟时间您可以使用 Bazel 分析 特征来判断 缓存命中次数

动态执行可与本地沙盒化策略以及永久性工作器搭配使用。永久性工作器会自动 搭配动态执行时,通过沙盒运行,且不能使用多路复用 工作器。在 Darwin 和 Windows 系统中,沙盒 策略可能比较缓慢您可以传递 --reuse_sandbox_directories 来减少 这些系统上创建沙盒的开销。

动态执行也可以使用 standalone 策略来运行,不过, standalone 策略在开始执行时必须获取输出锁, 实际上会阻止远程策略先完成。通过 --experimental_local_lockfree_output标志可以解决这个问题, 允许本地执行直接写入输出,但被 远程执行,如果先完成该任务。

如果动态执行的某个分支先完成但失败,则整个操作都会失败。这是有意为之,目的是防止本地和远程执行之间的差异不被注意到。

如需了解有关动态执行及其锁定工作原理的更多背景信息,请参阅 Julio Merino 的精彩博客 帖子

何时应使用动态执行?

动态执行需要某种形式的远程执行系统。目前无法使用仅限缓存的远程系统,因为缓存未命中会被视为操作失败。

并非所有类型的操作都非常适合远程执行。最佳 候选版本是指那些本来可以较快的 使用永久性工作器或快速运行的工作器 远程执行开销足以占用执行时间开始时间 每个本地执行的操作都会锁定一定数量的 CPU 和内存资源, 执行不属于这些类别的操作只会延迟执行 。

从版本 5.0.0-pre.20210708.4 开始,性能分析包含有关 Worker 执行的数据,包括在输掉动态执行争用后完成工作请求所花费的时间。如果您看到动态执行工作器线程 花费大量时间获取资源,或者花费大量时间 async-worker-finish,您可能会因为一些缓慢的本地操作而延迟 worker 线程。

在动态执行性能不佳时分析数据

在上面的配置文件(使用 8 个 Javac 工作器)中,我们看到许多 Javac 工作器 输掉比赛,并在async-worker-finish上完成了工作 线程。这是由于非工作器助记符占用了足够的资源 延迟工作器。

性能更出色的动态执行性能数据分析

当只有 Javac 通过动态执行运行时, 工人在开始工作后输掉比赛。

之前建议的 --experimental_spawn_scheduler 标志已废弃。 它会启用动态执行功能,并将dynamic设为 通常会导致这类问题。

性能

动态执行方法假定本地和远程有足够的资源可用,因此值得花费一些额外的资源来提升整体性能。但是,过度使用资源可能会降低 Bazel 本身的速度或 或对远程系统施加意外压力。您可以通过以下几种方式更改动态执行的行为:

--dynamic_local_execution_delay 会在远程分支启动后延迟本地分支的启动几毫秒,但前提是当前 build 期间存在远程缓存命中。这样一来,当大多数输出可能位于缓存中时,受益于远程缓存的 build 就不会浪费本地资源。根据缓存的质量 减少该值可以提高构建速度,但代价是会有更多本地资源 资源。

--experimental_dynamic_local_load_factor 是一项实验性高级资源管理选项。此值的取值范围为 0 到 1,0 表示关闭此功能。如果将此值设置为大于 0 的值,当有许多操作等待调度时,Bazel 会调整本地调度的操作数量。将其设置为 1 可让系统根据可用 CPU 数量(如 --local_cpu_resources 所示)调度尽可能多的操作。值越低,可运行的操作数量越多,调度的操作数量也会相应减少。这可能听起来不合常理,但使用优质遥控器 本地执行在运行很多操作时没有什么用处, 本地 CPU 更适合用来管理远程操作。

当远程分支已运行至少此时长时,--experimental_dynamic_slow_remote_time 会优先启动本地分支。通常,最近安排的操作会获得优先级,因为它最有可能赢得竞赛,但如果远程系统有时会挂起或花费很长时间,这可能会导致 build 继续运行。默认情况下,此功能处于停用状态,因为它可能会隐藏应修复的远程系统问题。请确保 监控远程系统性能(启用此选项)。

--experimental_dynamic_ignore_local_signals 可用于让遥控器 当本地生成元素因给定信号而退出时,分支将接管后续工作。这项功能主要与工作器资源限制(请参阅 --experimental_worker_memory_limit_mb--experimental_worker_sandbox_hardening--experimental_sandbox_memory_limit_mb)搭配使用,在这种情况下,如果工作器进程使用了太多资源,系统可能会将其终止。

JSON 轨迹配置文件包含一个 大量的效果相关图表,可帮助您找出改善广告效果的方法 性能和资源使用情况的权衡

问题排查

动态执行方面的问题可能很细微且难以调试,因为它们可能仅在本地和远程执行的某些特定组合下才会出现。--debug_spawn_scheduler 会从动态执行系统添加额外输出,这些输出有助于调试这些问题。您还可以调整 --dynamic_local_execution_delay 标志以及要计算的远程作业与本地作业的数量 可以更轻松地重现问题。

如果您在使用 standalone 进行动态执行时遇到问题 策略,尝试在没有 --experimental_local_lockfree_output 的情况下运行,或运行 本地操作沙盒这可能会稍微减慢 build 速度(如果您使用的是 Mac 或 Windows,请参阅上文),但可以消除一些可能导致失败的原因。