このページでは、Multiplex ワーカー、Multiplex 互換ルールの記述方法、特定の制限事項の回避策について説明します。
Multiplex ワーカーを使用すると、Bazel は単一のワーカー プロセスで複数のリクエストを処理できます。マルチスレッド ワーカーの場合、Bazel では使用するリソースが少なくなるため、同じか、パフォーマンスが向上します。たとえば、ワーカーごとに 1 つのワーカー プロセスを使用する代わりに、Bazel では、4 つの多重化されたワーカーで同じワーカー プロセスと通信して、リクエストを並列に処理できます。Java や Scala などの言語では、JVM のウォームアップ時間と JIT コンパイル時間が短縮されます。また、一般的には、同じタイプのワーカー間で 1 つの共有キャッシュを使用できます。
概要
Bazel サーバーとワーカー プロセスの間には、2 つのレイヤがあります。プロセスを並行して実行できる特定のニーモニックの場合、Bazel はワーカープールから WorkerProxy
を取得します。WorkerProxy
は、request_id
とともにリクエストをワーカー プロセスに順次転送します。ワーカー プロセスはリクエストを処理して、WorkerMultiplexer
にレスポンスを送信します。WorkerMultiplexer
はレスポンスを受信すると、request_id
を解析し、その後レスポンスを正しい WorkerProxy
に転送します。非多重化ワーカーと同様に、すべての通信は標準の入出力で行われますが、このツールは、ユーザーに表示される出力に stderr
をそのまま使用することはできません(下記を参照)。
各ワーカーにはキーがあります。Bazel は、鍵のハッシュコード(環境変数、実行ルート、ニーモニックで構成される)を使用して、使用する WorkerMultiplexer
を決定します。WorkerProxy
が同じハッシュコードを持つ場合、WorkerProxy
は同じ WorkerMultiplexer
と通信します。したがって、1 回の Bazel 呼び出しで環境変数と実行ルートが同じであると仮定すると、固有のニーモニックごとに WorkerMultiplexer
とワーカー プロセスは 1 つだけになります。通常のワーカーや WorkerProxy
を含むワーカーの合計数は、引き続き --worker_max_instances
によって制限されます。
Multiplex 互換ルールの記述
マルチプレックス ワーカーを利用するには、ルールのワーカー プロセスをマルチスレッド化する必要があります。Protobuf を使用すると、ストリームに複数のリクエストが蓄積されている場合でも、ルールセットで 1 つのリクエストを解析できます。ワーカー プロセスはストリームからのリクエストを解析するたびに、新しいスレッドでリクエストを処理する必要があります。異なるスレッドが完了してストリームへの書き込みが同時に行われる可能性があるため、ワーカー プロセスはレスポンスがアトミックに書き込まれるようにする必要があります(メッセージが重複しないようにする必要があります)。レスポンスには、処理するリクエストの request_id
を含める必要があります。
マルチプレックス出力の処理
Multiplex ワーカーは、シングルプレックス ワーカーよりも、出力の処理に注意を払う必要があります。stderr
に送信されたものはすべて、同じタイプのすべての WorkerProxy
で共有される 1 つのログファイルに記録され、同時リクエスト間でランダムにインターリーブされます。stdout
を stderr
にリダイレクトすることは良いアイデアですが、その出力を WorkResponse
の output
フィールドに収集しないでください。ユーザーがマングリングされた出力部分を示す可能性があるためです。ツールがユーザー指向の出力のみを stdout
または stderr
に送信する場合は、Multiplex ワーカーを有効にする前にその動作を変更する必要があります。
Multiplex ワーカーを有効にする
Multiplex ワーカーはデフォルトでは有効になっていません。ルールセットでは、アクションの execution_requirements
で supports-multiplex-workers
タグを使用して Multiplex ワーカーを有効にできます(supports-workers
タグでレギュラー ワーカーを有効にするのと同様です)。通常のワーカーを使用する場合と同様に、ワーカー戦略はルールセット レベル(--strategy=[some_mnemonic]=worker
など)または通常は戦略レベル(--dynamic_local_strategy=worker,standalone
など)のいずれかで指定する必要があります。追加のフラグは必要ありません。両方が設定されている場合は supports-multiplex-workers
が supports-workers
よりも優先されます。--noworker_multiplex
を渡すと、Multiplex ワーカーをグローバルに無効にできます。
メモリ プレッシャーを軽減してパフォーマンスを向上させるため、可能であれば Multiplex ワーカーを使用することをおすすめします。ただし、Multiplex ワーカーは、現時点でマルチプレックス サンドボックスを実装しない限り、動的実行と互換性がありません。サンドボックス化されていないマルチプレックス ワーカーを動的実行で実行しようとすると、代わりにサンドボックス化されたシングルプレックス ワーカーが暗黙的に使用されます。
Multiplex サンドボックス化
Multiplex ワーカーは、ワーカーの実装に明示的なサポートを追加することでサンドボックス化できます。シングルプレックス ワーカー サンドボックスは、各ワーカー プロセスを独自のサンドボックスで実行することで行えますが、Multiplex ワーカーは、複数の並列リクエスト間でプロセスの作業ディレクトリを共有します。Multiplex ワーカーのサンドボックス化を許可するには、ワーカーは、作業ディレクトリで直接ではなく、各リクエストで指定されたサブディレクトリに対する読み書きをサポートする必要があります。
Multiplex サンドボックスをサポートするには、ワーカーは WorkRequest
の sandbox_dir
フィールドを使用し、これをすべてのファイルの読み取りと書き込みの接頭辞として使用する必要があります。arguments
フィールドと inputs
フィールドはサンドボックス化されていないリクエストから変更されませんが、実際の入力は sandbox_dir
を基準とします。ワーカーは、arguments
と inputs
にあるファイルパスを変換して、この変更されたパスから読み取る必要があります。また、sandbox_dir
を基準とした相対出力をすべて書き込む必要もあります。これには「.」などのパスや、引数で指定されたファイル("argfile" 引数など)内のパスが含まれます。
ワーカーが Multiplex サンドボックス化をサポートすると、アクションの execution_requirements
に supports-multiplex-sandboxing
を追加することで、ルールセットでそのサポートを宣言できるようになります。--experimental_worker_multiplex_sandboxing
フラグが渡された場合、またはワーカーが動的実行で使用されている場合、Bazel は Multiplex サンドボックスを使用します。
サンドボックス化された Multiplex ワーカーのワーカー ファイルは、引き続きワーカー プロセスの作業ディレクトリを基準とします。したがって、ファイルがワーカーの実行と入力の両方に使用される場合は、flagfile 引数と、tools
、executable
、または runfiles
の両方で入力としてファイルを指定する必要があります。