モバイルゲーム分析プラットフォームの作成 - リファレンス アーキテクチャ

モバイルゲーム アプリケーションでは、プレーヤー テレメトリーとゲームイベントに関する膨大なデータが生成されます。このデータを使用して、プレーヤーの行動や、ゲームへのエンゲージメントを詳しく知ることができる可能性があります。モバイルゲームには、多数のクライアント デバイスが使用され、インターネット接続が不定期で低速であり、バッテリーや電源管理の問題が生じるという特性があり、プレーヤー テレメトリーやゲームイベントの分析は特有の課題に直面しています。

このリファレンス アーキテクチャでは、Google Cloud で大量のプレーヤー テレメトリー データを収集、保管、分析するための大まかな流れを提供します。

具体的には、モバイルゲーム イベントを解析するための、2 つのメイン アーキテクチャ パターンを学習します。

  • リアルタイム処理: ストリーミング処理パターンを使用して個々のイベントを処理します
  • 一括処理: バッチ処理パターンを使用して集約されたイベントを処理します

ゲーム テレメトリーのリファレンス アーキテクチャ

図 1: ゲーム テレメトリーのリファレンス アーキテクチャ

図 1 に、両方のパターンの処理パイプラインと、結果をさらに探索、可視化、共有するための、いくつかのオプション コンポーネントを示します。このリファレンス アーキテクチャは可用性が高く、データ量の増加に合わせてスケールできます。また、このアーキテクチャはデータ解析パイプラインのマネージド サービスのみで構成されており、仮想マシンを実行したり、オペレーティング システムを管理したりする必要はありません。特にこれは、ゲームサーバーが App Engine でユーザー認証を行う場合に有用です。この記事の残りの部分では、このアーキテクチャについて詳しく説明していきます。

ストリーミング パターンを使用したリアルタイム イベント処理

このセクションでは、さまざまなソースから多数のイベントを同時に取り込み、処理と解析を行うサンプル アーキテクチャ パターンについて説明します。処理はゲームでイベントが発生したときに行われるため、リアルタイムで応答し、決断を下すことができます。

多くのモバイルゲームでは、多数のイベント メッセージが生成されます。プレーヤーによってトリガーされるものや、設定された時刻にトリガーされるものなどがあります。その結果、データセットは無制限になり、処理するイベントの数を事前に把握することもできません。このため、なんらかのストリーミング実行エンジンを使用してデータを適切に処理する必要があります。

プレーヤーが強力なモンスターを倒すための冒険の旅に出かけて、邪悪な敵と戦うロール プレーイング ゲームのモバイルアプリがあるとします。プレーヤーの進捗を追跡するために、一般的なイベント メッセージにはプレーヤーの一意の ID、イベントのタイムスタンプ、冒険の進み具合を示すメトリック、プレーヤーの現在の状態などが含まれます。playerkillednpc のイベント ID を持つバトル終了イベント メッセージを表示させる場合、次の例のようになるかもしれません。

{
"eventTime":"2015-10-27T20:34:12.675362426+08:00",
"userId":"gamer@example.com",
"sessionId":"b6ff8881-0c30-9add-374c-c32052cee256",
"eventId":"playerkillednpc",
…
"attackRoll":17,
"damageRoll":13
}

この例はバトルに関連するイベントのものですが、イベント メッセージにはゲーム内購入イベントなど、ビジネスに関連するあらゆる情報が含まれる可能性があります。

将来、データに関して尋ねる必要が生じる質問の内容を予測することはできないため、可能な限り多くのデータポイントをログで記録するのが優れた戦略と言えます。これにより、将来データを照会するために必要なコンテキストをさらに得ることができます。たとえば、あるプレーヤーが 50 セントのゲーム内購入を行ったという情報と、冒険 15 でボスに立ち向かうために強力な呪文を購入したが、その購入の 30 分前にプレーヤーが続けて 5 回ボスによって倒されたという情報を比較して、どちらのほうがより洞察力が高いと言えるでしょうか。豊富なイベントデータを取得すると、ゲーム内で実際の行われていることに対して、さらに深い洞察を得ることができます。

メッセージ ソース: モバイルか、ゲームサーバーか

イベント メッセージのコンテンツ フィールドに関係なく、イベント メッセージを、モバイルアプリを実行しているエンドユーザー デバイスから直接 Pub/Sub 取り込みレイヤに送信するか、ゲームサーバーを介して送信するかを決定する必要があります。ゲームサーバーを介する主な利点は、認証と検証がアプリケーションによって処理されるということです。欠点は、モバイル デバイスから着信する大量のイベント メッセージを処理するために、その容量を処理する追加サーバーが必要になるということです。

ゲーム クライアントとゲームサーバー イベントのリアルタイム処理

図 2: ゲーム クライアントとゲームサーバーからのイベントのリアルタイム処理

データのソースに関係なく、バックエンド アーキテクチャは大部分が同じです。図 2 に示されているように、以下の 5 つの主要部分があります。

  1. リアルタイム イベント メッセージは、数百万台のモバイルアプリなど、多数のソースによって送信されます。
  2. 認証はゲームサーバーによって処理されます。
  3. Pub/Sub はこれらのメッセージを取り込み、一時的に保存します。
  4. Dataflow は JSON イベントを構造化されたスキーマベースのデータに変換します。
  5. このデータは BigQuery 分析エンジンに読み込まれます。

Pub/Sub: 大規模なイベントの取り込み

このロード作業を処理するには、これらのイベント メッセージを受信して一時的に保存できるスケーラブルなサービスが必要です。個々のイベントはサイズが非常に小さいため、メッセージの合計数のほうが全体的なストレージ要件よりも問題になります。

この取り込みサービスのもう 1 つの要件は、複数の出力方式に使用できるという点です。つまり、イベントは複数の宛先でコンシュームされる必要があります。最終的に、各宛先が新しいメッセージをフェッチするためにポーリングするキューとして動作するサービスと、受信時にイベントを積極的に送信する push メソッドの間で選択できます。

Pub/Sub サービスではこれらの機能がすべて提供されます。図 3 は、推奨される取り込みレイヤ、1 秒間に数百万件のメッセージを処理する機能、それらを最大 7 日間永続ストレージに保存する様子を示しています。Pub/Sub はパブリッシュ / サブスクライブ パターンを処理します。これにより、ユーザーは 1 人以上のパブリッシャーにメッセージを 1 つ以上のトピックに送信させることができます。トピックごとに複数のサブスクライバーを設定することもできます。

永続ストレージを使用する Pub/Sub のパブリッシュ / サブスクライブ モデル

図 3: 永続ストレージを使用する Pub/Sub のパブリッシュ / サブスクライブ モデル

トピックの数と、トピックのグループ化を選択できます。トピックの数と、作成する Cloud Dataflow パイプラインの数には直接的な関連性があるため、論理的に関連しているイベントをグループ化するのが最適です。たとえば、パブリッシャーは、単一のトピックに対して複数のパブリッシャーを持つ、個々のモバイル デバイスまたはゲームサーバーにすることができます。必要なことは、HTTPS で、適切にフォーマット設定されたメッセージを認証して送信できることのみです。

メッセージ(この場合はプレーヤーのテレメトリー イベント)は Pub/Sub サービスによって受信されると、すべてのトピック サブスクリプションがそのメッセージを取得するまで、メッセージ ストアに永続的に保存されます。

Dataflow ストリーミング パイプライン

Dataflow では、簡単な方法でデータ処理パイプラインを記述する高レベル言語を使用できます。Dataflow マネージド サービスを使用してこれらのパイプラインを実行できます。Dataflow パイプラインはストリーミング モードで実行され、サブスクリプションを介して到達すると、Pub/Sub トピックからメッセージを取得します。次に、Dataflow は必要なすべての処理を行ってから、メッセージを BigQuery テーブルに追加します。

この処理は、簡単な要素的オペレーション形式で実行できます。たとえば、すべてのユーザー名を小文字にしたり、ユーザー名のテーブルをプレーヤー統計に結合するなど、要素を他のデータソースに結合したりすることができます。

BigQuery テーブル形式への JSON メッセージの変換

図 4: BigQuery テーブル形式への JSON メッセージの変換

Dataflow は、入力データのリアルタイム検証など、任意の数のデータ処理タスクを実行できます。たとえば、有効範囲外の最大ヒットポイントを持つプレーヤーを強調表示するなど、不正行為の検出に使用できます。あるいは、イベント メッセージが適切に形式設定され、BigQuery スキーマと適合することを確認するなど、データ クレンジングにも使用されます。

図 4 の例では、ゲームサーバーの元の JSON メッセージをアンマーシャルし、BigQuery スキーマに変換します。重要なことは、この処置を実行するためにサーバーや仮想マシンを管理する必要がないことです。Dataflow がコンピューティング リソースを開始、実行、停止する作業を行い、パイプラインを並行処理します。また、ストリーミングとバッチ処理の両方に対して同じコードを再利用することもできます。

オープンソースの Dataflow SDK では、Dataflow プログラムの実行とは分離してパイプラインを実行できます。Dataflow プログラムによってパイプラインが作成され、この作成したコードによって、パイプライン ランナーが実行する一連のステップが生成されます。パイプライン ランナーには、Google Cloud 上の Dataflow マネージド サービス、SparkFlink などのサードパーティ ランナー サービス、ローカル環境でステップを直接実行するローカル パイプライン ランナーを使用できます。特に、ローカル パイプライン ランナーは開発とテストを行う際に有用です。

Dataflow は各要素が必ず 1 回だけ処理されるようにします。また、タイム ウィンドウトリガー機能を利用すると、Dataflow に送信される時間(処理時間)ではなく、実際に発生した時間(イベント時間)に基づいてイベントを集約できます。モバイル機器のインターネット接続問題やバッテリーの消耗によって一部のメッセージがソースから遅延する可能性はありますが、そのような場合でも最終的にはユーザー セッションごとにイベントをグループ化する必要があります。Dataflow に組み込まれたセッション ウィンドウ処理機能によって、これに対処できます。データのウィンドウ処理の詳しい説明については、The world beyond batch: Streaming 101 をご覧ください。

あるいは、イベントに Universally Unique Identifier(UUID)などの一意のセッション フィールドが含まれている場合、このキーを使用して関連するイベントをグループ化することもできます。使用する特定のシナリオに基づいて行うのが最適です。

BigQuery: 大規模なデータ解析用の完全に管理されたデータ ウェアハウス

BigQuery は 2 つの主要パーツで構成されています。その 1 つはストレージ システムであり、地理的冗長性と高可用性により、データの持続性を確保します。さらに、分析エンジンが配置されており、大量のデータセットに対して SQL のようなクエリを実行できます。BigQuery は、複数のテーブルを含めることができるデータセットにデータを編成します。BigQuery では、テーブルごとに定義されたスキーマが必要です。前のセクションでの Dataflow の主な役割は、内蔵 BigQuery コネクタを使用して JSON 形式の未処理イベントデータを BigQuery スキーマ構造に構造化することでした。

BigQuery テーブルにロードされたデータに対して対話式の SQL クエリを実行し、価値のあるインテリジェンスを得ることができます。BigQuery は非常に大規模な状況に対応するように作成されており、短い応答時間でペタバイト規模のデータセットに対して集約クエリを実行できます。これは、対話式分析に適しています。

データ可視化ツール

Google データポータルを使用すると、BigQuery をはじめとする広範なデータソースにアクセスするインタラクティブなダッシュボードを作成して共有できます。

BigQuery は、Looker など、広く使用されている BI と可視化ツールも統合します。最後に、BigQuery クエリを Google スプレッドシートMicrosoft Excel から直接実行できます。

バッチパターンを使用した一括処理

もう 1 つの主なパターンは、リアルタイムで処理する必要のない、大容量で制限付きのデータセットの定期的処理です。バッチ パイプラインはレポートの作成や、両方の長所を生かせるリアルタイム ソースとの組み合わせでよく使用されます。組み合わされるリアルタイム ソースの例としては、リアルタイム ストリーム パイプラインを介して送られてくる最新情報を含む信頼性のある履歴データがあります。

ゲームサーバーからのイベントとログのバッチ処理

図 5: ゲームサーバーからのイベントとログの一括処理

Cloud Storage は、容量の大きいファイルを保管する場所としておすすめです。これは、永続的で、可用性が高く、コスト効率の良いオブジェクト ストレージ サービスです。しかし、初めて Cloud Storage にデータを入れるにはどうすればよいでしょうか。これは、使用するデータソースによって異なります。次のいくつかのセクションでこのトピックについて説明します。オンプレミス、他のクラウド プロバイダ、Google Cloud という 3 つの異なるデータソース シナリオについて学習します。

シナリオ 1: オンプレミス サーバーからファイルを転送する場合

多数の方法を使用して、オンプレミスのデータセンターからログファイルを安全に転送できます。最も一般的な方法は、オープンソースの gsutil コマンドライン ユーティリティを使用して、反復的なファイル転送を設定する方法です。gsutil コマンドにはいくつかの便利な機能が備わっています。たとえば、多数のファイルがある場合に有用なマルチスレッドの並列アップロードや、ローカル ディレクトリの自動同期、大容量ファイルに適した再開可能なアップロード機能などがあります。ファイルの容量が非常に大きいときはファイルを分割し、並列アップロードを行えます。これらの機能により、アップロード時間が短縮され、可能な限り多くのネットワーク接続を使用できるようになります。

インターネット帯域幅が不十分であるために適時にアップロードできない場合、ダイレクト ピアリングまたはキャリア ピアリングを使用して、Google Cloud に直接接続できます。あるいは、物理的な媒体を送信するほうがよい場合は、オフラインの Transfer Appliance の使用を検討してください。

シナリオ 2: 他のクラウド プロバイダからファイルを転送する場合

一部のログファイルは、他のクラウド プロバイダを使用して保存される場合があります。おそらくそこでゲームサーバーを実行し、そのクラウド プロバイダのストレージ サービスにログを出力します。あるいは、デフォルトのストレージ ターゲットがあるサービスを使用します。たとえば、Amazon Cloudfront(Content Delivery Network サービス)は、そのログを Amazon S3 バケットに保存します。幸いなことに、Amazon S3 から Cloud Storage へのデータの移動は簡単です。

大量のファイルを毎日 Amazon S3 から Cloud Storage に転送する場合、Storage Transfer Service を使用して、Amazon S3 や HTTP/HTTPS サービスなどのソースからファイルを転送できます。転送が定期的に繰り返し行われるように設定できます。また、Storage Transfer Service ではいくつかの高度なオプションがサポートされています。このサービスは大手クラウド プロバイダ間の大規模ネットワーク帯域幅を活用し、高度な帯域幅最適化技術を使用して非常に高速な転送速度を実現します。

1 回の転送が 1 TB~10 TB またはそれ以上になるなら、このサービスの使用をおすすめします。これにより、シナリオ 1 で述べた gsutil ツールを複数のサーバーで実行する場合の運用上のオーバーヘッドを軽減できます。小規模な転送や、1 日に複数回データを移動する必要がある場合は、シナリオ 1 で述べた gsutil ツールの使用を検討してください。

シナリオ 3: データが Google Cloud にすでに存在する場合

場合によっては、必要なデータがデフォルトで自動的に Cloud Storage に保存されていることもあります。たとえば、Google Play Store からのデータ(Reviews、Financial Reports、Installs、Crash、Application Not Responding(ANR)レポートなど)は、Google Play Developer アカウントに基づいて、Cloud Storage バケットで入手できます。このような場合、別のバケットにデータを移動する理由がなければ、エクスポート先の元のバケットにデータを保持できます。

非同期転送サービス パターン

長期的でスケーラブルな手法として、1 つ以上のキューとメッセージング機能を使用して、イベントまたはトリガーに基づいて転送を開始する非同期転送サービス パターンの実装があります。たとえば、新しいログファイルがディスクまたはソースファイル ストアに書き込まれると、メッセージがキューに送信され、ワーカーはそのオブジェクトを Cloud Storage に正常に転送し、正常に完了した場合にのみキューからメッセージを削除するというジョブを引き受けます。

代替バッチパターン: Cloud Storage から BigQuery への直接ロード

Cloud Storage と BigQuery の間に Dataflow を使用するのは必ずしも必要なことでしょうか。スキーマを指定し、ロードジョブを開始することで、Cloud Storage の JSON ファイルからファイルを直接ロードできます。あるいは、Cloud Storage バケットで CSV、JSON、または Datastore のバックアップ ファイルを直接クエリできます。これらは、まず使ってみるという段階では悪くない手法かもしれませんが、Dataflow を使用した場合は次のメリットがあります。

  • ストレージへの commit 前にデータを変換する。たとえば、BigQuery にロードする前に、異なるタイプのデータを別個のテーブルにグループ化してからデータを集約できます。これは、クエリ対象の行数を最小限に抑えることで、BigQuery コストを削減するのに役立つ可能性があります。リアルタイムのシナリオでは、Dataflow を使用して個々のセッション内、またはギルドやチームのような集団内のリーダーボードを計算できます。

  • Dataflow で作成されたストリーミングとバッチデータ パイプラインを相互に置き換えて使用する。データソースとデータシンクを変更します(例: Pub/Sub から Cloud Storage へ)。同じコードが両方のシナリオで機能します。

  • データベース スキーマの観点から柔軟性を高める。たとえば、時間の経過とともにイベントに追加フィールドを追加してきた場合、追加の未処理 JSON データをスキーマの catch-all フィールドに追加して、BigQuery JSON クエリ機能を使用してそのフィールド内をクエリできます。その後、ソースイベントで厳密に異なるスキーマが必要であっても、複数の BigQuery テーブルに対してクエリを実行できます。これを図 6 に示します。

未処理 JSON で新しいイベント フィールドを取得するための追加列

図 6: 未処理 JSON で新しいイベント フィールドを取得するための追加列

リファレンス アーキテクチャに応じた操作上の考慮事項

パイプラインを確立して作成したら、パフォーマンスと、発生する可能性のある例外をモニタリングすることが重要です。Dataflow のモニタリング ユーザー インターフェースでは、データ パイプライン ジョブを視覚的に表示することができ、主要な指標が示されます。図 7 は、このサンプル スクリーンショットです。

組み込み Dataflow モニタリング コンソール

図 7: 組み込み Dataflow モニタリング コンソール

Dataflow コンソールは、パイプライン実行グラフに加え、各ステップで処理されているメッセージ数、予測されるシステムラグ、データ ウォーターマークなどの現在のパフォーマンス統計に関する情報を提供します。補足として、Dataflow は Cloud Logging サービスと統合されています。図 8 はそのサンプルとなるスクリーンショットです。

Cloud Logging は Dataflow と統合

図 8: Cloud Logging は Dataflow と統合

その他の資料と追加リソース