コードベースが大きい場合、依存関係のチェーンが非常に深くなる可能性があります。 単純なバイナリでさえ、数万ものビルド ターゲットに依存することが少なくありません。ちなみに 妥当な量で構築を完了することは不可能です。 時間のかかるプロセスです。ビルドシステムは、基盤となるインフラストラクチャを マシンのハードウェアに課せられる物理法則です。そのための唯一の方法は 分散ビルドをサポートするビルドシステムを使用すると、 システムが実行している作業を、任意のスケーラブルな あります。システムの処理をある程度の小さなサイズに分割したと仮定すると、 これにより、任意のビルドを完了できます(詳細は後ほど説明します)。 お支払い可能な範囲で迅速に行えますこのスケーラビリティは 開発に取り組んできたのが、アーティファクト ベースのビルドシステムです。
リモート キャッシュ
最もシンプルな分散ビルドは、リモートビルドのみを使用する キャッシュ を使用します。
図 1. リモート キャッシュを示す分散ビルド
ビルドを実行するすべてのシステム(デベロッパー ワークステーションと 継続的インテグレーション システムにより、共通のリモート キャッシュへの参照を共有 あります。このサービスは、高速かつローカルな短期ストレージ システムになります。 Google Cloud Storage などのクラウド サービスで、ユーザーが必要に応じて 直接または依存関係としてアーティファクトをビルドする場合、 リモート キャッシュに移動して、そのアーティファクトがすでに存在するかどうかを確認します。もしそうならば、それは アーティファクトをビルドせずにダウンロードできます。そうでない場合、システムは 結果をキャッシュにアップロードします。つまり 頻繁に変更されない低レベルの依存関係は、一度ビルドして共有できます。 ユーザーごとに構築でき、ユーザーごとに再構築する必要がありません。Google では、 ゼロから構築するのではなく、キャッシュから提供されるため、 ビルドシステムの実行にかかる費用を削減できます
リモート キャッシュ システムが機能するには、ビルドシステムが、 完全に再現可能です。つまり、どのビルド ターゲットでも、 そのターゲットへの入力のセットを決定し、同じ入力セットが どのマシンでもまったく同じ出力が生成されますこれが唯一の アーティファクトのダウンロードの結果が結果と同じであることを確認する 考えてみましょうキャッシュ内の各アーティファクトは、 ターゲットとその入力のハッシュの両方をキーとしているので、 エンジニアが同じターゲットに対して異なる変更を同時に加えることができた リモート キャッシュにすべてのアーティファクトが保存され、 適切に構成する必要があります。
もちろんリモートキャッシュを活用するには アーティファクトの構築よりも高速である必要があります。そうとは限りません キャッシュサーバーとビルドを実行するマシンが 離れている場合は特にそうですGoogle の ビルドをすばやく共有できるように、ネットワークとビルドシステムは 表示されます。
リモート実行
リモート キャッシュは真の分散ビルドではありません。キャッシュが失われた場合や すべての再構築が必要な低レベルの変更を行う場合も、 ビルド全体をローカルのマシン上で実行できます。本当の目的は リモート実行では、ビルドを行う実際の作業が分散され、 スケーリングできます図 2 は、リモート実行システムを示しています。
図 2. リモート実行システム
各ユーザーのマシンで実行されるビルドツール(ユーザーは人間か エンジニアや自動ビルドシステムなど)は、リクエストを中央のビルドマスターに送信します。 ビルドマスターはリクエストをコンポーネント アクションとスケジュールに分割する スケーラブルなワーカープールでこれらのアクションを 実行できます各ワーカー ユーザーが指定した入力で要求されるアクションを実行し、 結果のアーティファクトを書き出します。これらのアーティファクトは、 必要とするアクションをマシンで実行し、それを最終出力が ユーザーに送信されます
このようなシステムの実装で最も厄介なのは、通信の管理と ワーカー、マスター、ユーザーのローカルマシン間の 接続トラフィックを保護しますワーカーは 他のワーカーによって生成された中間アーティファクトと、 ユーザーのローカルマシンに送り返す必要があります。これを行うには、Google Cloud の 前述の分散キャッシュの一番上にワーカーが その依存関係をキャッシュから読み取りますマスター ブロック 依存するすべてのタスクが完了するまで キャッシュから入力を読み取ることができます。最終的な成果物は、 キャッシュに保存し、ローカルマシンにダウンロードできるようにします。なお、 ユーザーのソースツリーのローカルの変更をエクスポートし、 ワーカーはビルド前に変更を適用できます
そのためには、ここで説明したアーティファクト ベースのビルドシステムのすべての部分が、 統合する必要がありますビルド環境は完全に 自己記述型であるため、人間の介入なしにワーカーをスピンアップできます。ビルド 完全に自己完結型でなければなりません。これは、各ステップが 別のマシンで実行することもできます出力は完全に確定的である必要があるため、 各ワーカーは他のワーカーから受け取った結果を信頼できますそのような タスクベースのシステムでは、このような保証を提供することは 信頼できるリモート実行システムをほぼ不可能に 1 です。
Google での分散ビルド
2008 年以来、Google は分散ビルドシステムを使用して、 リモート キャッシュとリモート実行を示しています(図 3 を参照)。
図 3. Google の分散ビルドシステム
Google のリモート キャッシュは ObjFS と呼ばれます。コンテナは、アプリケーション、 本番環境のフリート全体で分散された Bigtable で出力を構築する objfsd という名前のフロントエンド FUSE デーモンと、各デベロッパーの あります。FUSE デーモンを使用すると、エンジニアはビルド出力をまるで ワークステーション上に保存された通常のファイルでしたが、ファイルの内容はそのままでした。 ネットワークから直接リクエストされた少数のファイルについてのみ、 できます。ファイルのコンテンツをオンデマンドで提供することで、ネットワークとディスクの両方を大幅に削減 また、データを保存したときよりも 2 倍の速さでシステムを構築できます。 デベロッパーのローカル ディスクにあるすべてのビルド出力。
Google のリモート実行システムは Forge と呼ばれています。Blaze の Forge クライアント (Bazel の内部で同等のもの)が呼び出され ディストリビューターは、各アクションのリクエストを データセンターとほぼ同じです。スケジューラはアクションのキャッシュを維持 これにより、アクションがすでに完了している場合はすぐにレスポンスが返されます。 システムの他のユーザーが作成したファイルです。そうでない場合は、アクションを 作成します。エグゼキュータ ジョブの大規模なプールが、このキューから継続的にアクションを読み取ります。 ObjFS Bigtable に直接保存できますこれらの エグゼキュータで結果をダウンロードし、今後のアクションに利用できる エンドユーザーが objfsd を通じて提供します。
最終的に、あらゆるビルドを効率的にサポートするようにスケーリングできるシステムが完成します。 実践した例ですGoogle のビルドの規模は実に巨大です。Google 何百万ものビルドを実行して数百万のテストケースを実行し 1 日あたり数十億行のソースコードからビルド出力が取得されています。Google は、 このようなシステムにより、エンジニアは複雑なコードベースを迅速に構築できます。また、 膨大な数の自動ツールやシステムを実装するために 構築できます。