コンテンツに移動
アプリケーション開発

Cloud Pub/Sub と GKE を使用して大規模な C++ ワークロードを実行

2021年1月19日
Google Cloud Japan Team

※この投稿は米国時間 2021 年 1 月 7 日に、Google Cloud blog に投稿されたものの抄訳です。

この数年間、私たちは Google Cloud を C++ ワークロードを実行するための最適なプラットフォームにすべく取り組んできました。これまでの進捗状況を示すために、Cloud Pub/SubCloud Storage の両方で C++ を使用して、Google Kubernetes Engine(GKE)で実行されるスケーラビリティの高いジョブキューを構築する方法についてご紹介します。

このようなアプリケーションでは、多くの場合、優れたパフォーマンスを実現するために多数のコンピューティング ノードに作業を分散させる必要があります。パブリック クラウド プロバイダの魅力の一つとして挙げられるのが、こうした並列計算のオンデマンドでのスケジュール設定や、必要に応じて計算を行うクラスタのサイズを拡大したり、実行されなくなったときにサイズを縮小したりする機能です。本投稿では、Pub/Sub と GKE を使用して、C++ アプリケーションにおいてこの可能性を実現する方法をご説明します。

大規模な計算を行うための一般的なパターンといえるのがジョブキューです。作業はキュー内のメッセージで表され、多くのワーカー アプリケーションが処理のためにキューからアイテムを pull します。最近リリースされた Pub/Sub(CPS)C++ クライアント ライブラリを使用すると、このパターンを簡単に実装できます。また、GKE 自動スケーリングを使用することで、このようなワークロードを実行するクラスタを必要に応じて拡大、縮小できるため、C++ のデベロッパーは面倒なクラスタ管理から解放され、アプリケーションの改善に多くの時間を費やせるようになります。

サンプル アプリケーション

この例では、何百万個もの Cloud Storage オブジェクトを作成します。なんらかの計算を行い(例: 大規模なデータセットの一部を分析)、その結果を別々の Cloud Storage オブジェクトに保存する並列アプリケーションをモデル化しています。このワークロードは、一部の特殊なシミュレーションよりも理解しやすいと思われますが、まったく手がかからないわけではありません。負荷テスト用に随時、大規模な合成データセットを作成する必要があります。

概要

基本的な考え方は、作業を少数の作業アイテムに分割することです。たとえば、「このプレフィックスで 1,000 個のオブジェクトを作成する」といった具合です。コマンドライン ツールを使用してこのような作業アイテムを Pub/Sub トピックにパブリッシュし、作業アイテムを実行する任意の数のワーカーノードに確実に配信します。ワーカーノードの実行には GKE を使用します。GKE は需要に基づいて自動的にクラスタをスケールし、必要に応じて障害発生後にワーカーノードを再起動します。

Pub/Sub は at-least-once 配信を提供し、ワーカーノードは GKE により再起動される可能性があることから、これらの作業アイテムはべき等にすることが重要です。つまり、作業アイテムを複数回実行しても 1 回実行しても、同じオブジェクトが Cloud Storage に生成されます。

この例のコードは、こちらの GitHub リポジトリで入手できます。

作業アイテムの送信

作業アイテムは簡単な C++ 構造体で表されます。

読み込んでいます...

わずか数行のコードで、この構造体を Pub/Sub メッセージに変換できます。

読み込んでいます...

パブリッシャーを使用してメッセージが送信されるため、メッセージのバッチ処理や再試行を行う必要はありません。こうした細かい作業はライブラリが処理します。

読み込んでいます...

作業アイテムの読み取り

作業アイテムを読み取るには、サブスクライバーを作成し、それにコールバックを関連付けます。アプリケーションがメッセージを処理する準備ができるまで、Pub/Sub サービスでメッセージを保持するようにするため、一度に数個のメッセージのみを読み取るようにサブスクリプションを構成します。

読み込んでいます...

この関数を実行しているアプリケーションがクラッシュしたり、GKE による再スケジュールが必要になったりした場合、Pub/Sub サービスはメッセージを新しいインスタンスに再配信します。これは、process_one_item() 関数が複数回呼び出された場合でも同じ出力を生成するため、同じ結果となります。

読み込んでいます...

アプリケーションのコンパイル

GitHub リポジトリには、このコードを Docker イメージにコンパイルするために必要な CMake と Docker のスクリプトが含まれています。ここでは Cloud Build を使用してビルドし、有用な作業を行うためにワークステーションを開放します(決してビデオゲームを楽しむためではありません)。

読み込んでいます...

コマンドの初回実行時、ソースからすべての依存関係を構築するため、しばらく時間がかかる場合があります。中間結果はキャッシュに保存され、以降の実行において時間を節約するために使用されます。

GKE へのデプロイ

Docker イメージが作成されたら、以前に作成した GKE クラスタにアプリケーションをデプロイできます。ここでは、スクリプトを使用して yaml ファイルを生成します。

読み込んでいます...

次に、必要に応じて GKE が自動スケーリングするよう指定します。

読み込んでいます...

これにより、GKE クラスタ内のアプリケーションの少なくとも 1 つのレプリカが開始され、CPU 負荷が 50% を超えた場合に、追加のレプリカ(最大 200 個)を作成するようクラスタが構成されます。

まとめ

Pub/Sub を作業キューとして使用すると、並列 C++ アプリケーションの実装を簡素化できます。Pub/Sub はアプリケーション間で作業アイテムを分散し、ワーカーノードが予期せず停止した場合に再試行して、ワーカーノード数の増加に応じてスケールアップします。さらに、ワーカーノードを GKE にデプロイできるため、ワーカー アプリケーションを実行するためのフリーの仮想マシンの検索や作成、それらの仮想マシンでのワーカー アプリケーションのスケジュール設定、必要に応じたコンピューティング ノードの数の増減が自動的に行われます。C++ アプリケーションに小さな作業アイテムが多数あり、それらをべき等にできる場合は、タスクのスケジュール設定に Pub/Sub と GKE の使用をご検討ください。

ご自身の環境でこれらの手法をお試しになる場合は、GitHub からサンプルをダウンロードしてください。コードを参照して、独自のアプリケーションで使用することも可能です。

-ソフトウェア エンジニア Carlos O'Ryan

-ソフトウェア エンジニア Greg Miller

投稿先