本页介绍了多重工作器、如何编写兼容多重规则的规则以及特定限制的解决方法。
多重工作器允许 Bazel 通过单个工作器进程处理多个请求。对于多线程工作器,Bazel 可以使用较少的资源来实现相同或更高的性能。例如,Bazel 可以让每个工作器进程与同一个工作器进程通信,然后该工作器进程可以并行处理请求,而不是每个工作器只有一个工作器进程。对于 Java 和 Scala 等语言,可以节省 JVM 预热时间和 JIT 编译时间,并且一般而言,它允许在同一类型的所有工作器之间使用一个共享缓存。
概览
Bazel 服务器和工作器进程之间有两个层。对于某些可以并行运行进程的助记符,Bazel 会从工作器池中获取 WorkerProxy
。WorkerProxy
将请求连同 request_id
一起转发到工作器进程,工作器进程会处理请求并将响应发送到 WorkerMultiplexer
。WorkerMultiplexer
收到响应后,会解析 request_id
,然后将响应转发回正确的 WorkerProxy
。与非多路复用工作器一样,所有通信均通过标准输入/输出完成,但该工具不能只将 stderr
用于用户可见的输出(见下文)。
每个工作器都有一个密钥。Bazel 会使用密钥的哈希代码(由环境变量、执行根和记忆符号组成)来确定要使用的 WorkerMultiplexer
。如果 WorkerProxy
具有相同的哈希代码,则它们与相同的 WorkerMultiplexer
进行通信。因此,假设在一次 Bazel 调用中,环境变量和执行根相同,则每个唯一的助记器只能有一个 WorkerMultiplexer
和一个工作器进程。工作器(包括常规工作器和 WorkerProxy
的总数)仍受 --worker_max_instances
的限制。
编写兼容多重规则
该规则的工作器进程应为多线程,以利用多重工作器。借助协议缓冲区,规则集可以解析单个请求,即使数据流中可能有多个请求堆积也是如此。每当工作器进程解析来自流的请求时,它都应在新线程中处理请求。由于不同的线程可以同时完成并向数据流写入数据,因此工作器进程需要确保响应以原子方式写入(消息不重叠)。响应必须包含其正在处理的请求的 request_id
。
处理多重输出
与单一复杂工作器相比,多工作器工作器需要更谨慎地处理其输出。发送到 stderr
的任何内容都将放入同一类型的所有 WorkerProxy
共享的单个日志文件中,并在并发请求之间随机交错。尽管最好将 stdout
重定向到 stderr
,但请勿将该输出收集到 WorkResponse
的 output
字段中,因为这可能会导致用户输出内容被损坏。如果您的工具仅向 stdout
或 stderr
发送面向用户的输出,则您需要先更改该行为,然后才能启用多重工作器。
启用多重工作器
默认情况下,不会启用多重工作器。规则集可以在操作的 execution_requirements
中使用 supports-multiplex-workers
标记来启用多重工作器(就像 supports-workers
标记启用常规工作器一样)。与使用常规工作器时一样,需要在规则集级别(例如 --strategy=[some_mnemonic]=worker
)或一般在策略级别(例如 --dynamic_local_strategy=worker,standalone
)指定工作器策略。无需额外的标志,如果设置了两个标志,supports-multiplex-workers
的优先级高于 supports-workers
。您可以通过传递 --noworker_multiplex
在全球范围内关闭多重工作器。
建议您尽可能使用多组工作器来减少内存压力并提高性能。但是,多重工作器目前与动态执行不兼容,除非它们实现了多重沙盒。如果尝试在动态执行模式下运行未经过沙盒化的多路复用工作器,系统将静默地使用在沙盒中运行的单复杂工作器。
多重沙盒
通过在工作器实现中添加对多重工作器的明确支持,您可以对它们进行沙盒化。虽然可以通过在各自的沙盒中运行每个工作器进程来完成单复杂工作器沙盒,但多重工作器可以在多个并行请求之间共享进程工作目录。如需允许对多重工作器进行沙盒化,工作器必须支持读取和写入每个请求中指定的子目录,而不是直接写入其工作目录。
如需支持多重沙盒,工作器必须使用 WorkRequest
中的 sandbox_dir
字段,并将其用作所有文件读写的前缀。
虽然 arguments
和 inputs
字段与未沙盒化的请求保持不变,但实际输入是相对于 sandbox_dir
而言的。工作器必须转换在 arguments
和 inputs
中找到的文件路径,以便从这个修改后的路径读取数据,并且还必须写入相对于 sandbox_dir
的所有输出。
其中包括路径(如“.”)以及在参数中指定的文件(例如 argfile 参数)中找到的路径。
工作器支持多重沙盒后,规则集可以通过将 supports-multiplex-sandboxing
添加到操作的 execution_requirements
来声明此支持。如果传递了 --experimental_worker_multiplex_sandboxing
标记,或者工作器与动态执行机制结合使用,则 Bazel 会使用多重沙盒。
沙盒化多路复用工作器的工作器文件仍然是相对于工作器进程的工作目录的。因此,如果文件既用于运行工作器又用作输入,则必须在 flagfile 参数以及 tools
、executable
或 runfiles
中将其指定为输入。