このページでは、マルチプレックス ワーカー、マルチプレックス対応のルールの作成方法、特定の制限事項の回避策について説明します。
マルチプレックス ワーカーを使用すると、Bazel は 1 つのワーカー プロセスで複数のリクエストを処理できます。マルチスレッド ワーカーの場合、Bazel はより少ないリソースを使用して、同じパフォーマンスまたはそれ以上のパフォーマンスを実現できます。たとえば、Bazel では、ワーカーごとに 1 つのワーカー プロセスを使用する代わりに、同じワーカー プロセスと通信する 4 つの多重化されたワーカーを用意し、リクエストを並列処理できます。Java や Scala などの言語では、これにより JVM のウォームアップ時間と JIT コンパイル時間が短縮されます。また、通常は、同じタイプのすべてのワーカー間で 1 つの共有キャッシュを使用できます。
概要
Bazel サーバーとワーカー プロセスの間には 2 つのレイヤがあります。プロセスを並列で実行できる特定の Mnemonic の場合、Bazel はワーカープールから WorkerProxy
を取得します。WorkerProxy
は、request_id
とともにリクエストをワーカー プロセスに順番に転送します。ワーカー プロセスはリクエストを処理し、WorkerMultiplexer
にレスポンスを送信します。WorkerMultiplexer
がレスポンスを受信すると、request_id
を解析し、レスポンスを正しい WorkerProxy
に転送します。非多重化ワーカーと同様に、すべての通信は標準の入出力で行われますが、ユーザーに表示される出力に stderr
を使用できません(下記を参照)。
各ワーカーにはキーがあります。Bazel は、キーのハッシュコード(環境変数、実行ルート、メモニカで構成)を使用して、使用する WorkerMultiplexer
を決定します。WorkerProxy
は、同じハッシュコードを持つ場合、同じ WorkerMultiplexer
と通信します。したがって、単一の Bazel 呼び出しで環境変数と実行ルートが同じであると仮定すると、各一意の mnemo には WorkerMultiplexer
とワーカー プロセスを 1 つずつしか設定できません。通常のワーカーと WorkerProxy
を含むワーカーの合計数は、引き続き --worker_max_instances
で制限されます。
マルチプレックス対応のルールを作成する
マルチプレックス ワーカーを活用するには、ルールのワーカー プロセスをマルチスレッドにする必要があります。Protobuf では、ストリームに複数のリクエストが積み重なっている場合でも、ルールセットで 1 つのリクエストを解析できます。ワーカー プロセスがストリームからリクエストを解析するたびに、新しいスレッドでリクエストを処理する必要があります。異なるスレッドが同時に完了してストリームに書き込む可能性があるため、ワーカー プロセスはレスポンスがアトミックに書き込まれていることを確認する必要があります(メッセージが重複しないようにします)。レスポンスには、処理するリクエストの 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」引数など)にあるパスが含まれます。
ワーカーがマルチプレックス サンドボックスをサポートしたら、ルールセットでアクションの execution_requirements
に supports-multiplex-sandboxing
を追加して、このサポートを宣言できます。--experimental_worker_multiplex_sandboxing
フラグが渡された場合、またはワーカーが動的実行で使用されている場合、Bazel はマルチプレックス サンドボックスを使用します。
サンドボックス化されたマルチプレックス ワーカーのワーカー ファイルは、引き続きワーカー プロセスの作業ディレクトリを基準としています。したがって、ワーカーの実行と入力の両方にファイルを使用する場合は、flagfile 引数と tools
、executable
、runfiles
の両方で入力として指定する必要があります。