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