Cloud SQL for MySQL の第 2 世代をモバイルゲーム バックエンド データベースとして使用する

Last reviewed 2022-10-28 UTC

オンライン ゲームのバックエンドを作成するための十分にテストされたパターンでは、MySQL などのリレーショナル データベースを使用します。このデータベースには、ゲームの世界の状態と重要な永続性データが保存されます。基本的にセッション ベースのゲームでは、データベースには、対戦の最終的な結果以上に複雑なものは何も保存しません。大規模な、永続的な世界の多人数同時参加型オンライン(MMO)ゲームでは、データベースはプレーヤーの進行と在庫を格納した非常に複雑な相互関連テーブルのセットになる場合があります。パックエンドのデータベース層でのクエリの速度によって、ゲーム クライアントの応答性に影響が出ることをユーザーは直接実感します。

このパターンは馴染み深いものですが、多くのゲーム開発チームには専任のデータベース管理者が存在せず、またデータベースのサイズが巨大化し、モデル化した関係が複雑になるため、管理は、多数のチームが専任で行う作業になる可能性があります。小規模から中規模の非同期ターン制モバイルゲームでは、Google Cloud SQL のようなデータベースが優れた選択肢になり得ます。Cloud SQL for MySQL 第 2 世代は、堅実なパフォーマンス、最小限のオペレーション、自動化バックアップを備え、完全にホストされたマネージド MySQL インスタンスを提供します。

サービス フロントのデータベース パターンの設計

データベース アーキテクチャの概要

マイクロサービス パラダイムは、モバイルゲーム データベース バックエンドにとって有益です。共通の設計では、データベース サービスが前面にあるデータベースが存在します。データベース サービスは、ゲーム フロントエンドからクエリ リクエストを受け取り、データベースに対してこれらのクエリを実行し、結果を返すワーカー プロセスによって形成されています。

サービス フロントのデータベース パターンの利点

ユーザーのゲームサービスの代わりに中間的なサービスがデータベースにクエリを行うことには、いくつかの利点があります。

  • 可用性の向上 - 多くの場合、データベースでは同時接続数が制限されます。サービスを使用すると、データベースにリクエストを行うことができるゲームサーバー数が、許可される最大接続から切り離されます。
  • フォールト トレランス - データベースで問題が発生した場合、データベース サービスを作成して一時的にリクエストを処理できます。
  • 最適化されたリクエスト - データベース サービスは、データベース リクエストを最適化して、以下を提供できます。
    • クエリの検証。
    • クエリの優先順位設定。
    • クエリ速度フローの制御。
    • インメモリ キャッシュ、リードスルー キャッシュ。
  • データベース抽象化 - サービス契約を遵守している限り、フロントエンドのゲームサーバーを変更することなく、データベース サービスと、その背後にあるデータベースを交換できます。この設計により、開発環境や QA 環境で別のデータベースを使用すること、または本番環境において別のデータベース テクノロジーに移行することが可能になります。

サービス フロントのゲーム用データベース パターン

次の図は、Google Cloud Platform サービスを使用して、サービスが前面にある堅牢なデータベース パターンを作成する方法を示しています。

Google Cloud Platform を使用するデータベース パターン

次のコンポーネントを使用して、堅牢なサービス フロントのデータベース パターンを作成できます。

  • 専用ゲームサーバー / フロントエンド - ゲーム クライアント アプリケーションは、ゲームサーバーに直接接続し、フロントエンド サービスとします。専用ゲームサーバーは通常カスタム実行可能で、ゲームエンジンで構築されており、Google Compute Engine VM などの仮想化されたハードウェア上で実行する必要があります。オンライン インタラクションを HTTP スタイルのリクエスト / レスポンス セマンティクスでモデル化できるゲームを作成する場合は、Google App Engine もよく適合します。

  • データベース サービスとのゲームサーバー コミュニケーション - これは、作成、読み取り、更新、削除(CRUD)アクセス スタイルを使用してモデル化されることが多く、Compute Engine 上の REST API または gRPC エンドポイントが有力な選択肢になります。

  • データベース ワーカープールに対する API/RPC エンドポイント コミュニケーション - 従来のキューイングの場合、よくある選択肢として、RabbitMQZeroMQ など、セルフマネージド型のオープンソース キューイング ミドルウェアがあります。Cloud Platform では、安全で耐久性のあり、可用性の高い Google Cloud Pub/Sub を使用できます。これにより、サーバーを管理する必要のないマネージド キューイング ソリューションが提供されます。

  • Cloud SQL 第 2 世代に接続するデータベース ワーカー - データベース ワーカーは、最新の MySQL アクセス方式を提供する任意の言語で記述できます。これらのワーカーは、Compute Engine 上で手動で管理するか、または Docker コンテナでパッケージ化し、Google Kubernetes Engine 上の Kubernetes DSL を使用して簡単に管理することもできます。

Cloud SQL 第 2 世代の使用時には、次に示す多少の制限があります。

  • 10 TB のデータベース サイズの制限。
  • 同時接続 4,000 の接続制限。
  • レプリカはサポートされるものの、NDB(シャーディング)サポートの欠落。

これらの項目を追加する手順は次のとおりです。

  • 保存するデータ量を最適化するデータモデルを選択します。

  • まれにしかアクセスしないデータをメイン データベースから Google BigQuery などのデータ ウェアハウスに移動するプロセスを組み込みます。

  • ゲームサーバーがマイクロサービスを通してデータベースにアクセスするパターンを使用します。ゲームサーバーがデータベースに直接アクセスするため、プレーヤーの数が十分に妥当な場合であっても、データベース層をゲームサーバーから切り離すことには、キューイング、クエリレートの平準化、接続エラー トレランスなど、多数の利点があります。さらに、ゲームがよく使用されるようになった後に独自のデータベース アクセス層を追加しようとすると、ダウンタイムが発生する可能性があり、収入が失われる可能性があります。

  • データベースの読み取り専用レプリカに対してゲーム アナリティクスとプレーヤー テレメトリーを実行します。これにより、アナリティクスがデータベースの応答性に影響を及ぼすのを防止できます。Cloud SQL for MySQL 第 2 世代では、標準 MySQL レプリケーションが可能であり、2 番目のインスタンスをアナリティクス クエリ用に適切な大きさにして、コストを低く保つことができます。

サンプル デザイン: 大規模なシングルプレーヤー ソーシャル(MASS)ゲーム

過去 10 年間にわたって出現した 1 つのゲーム パラダイムでは、非常に多数のシングル プレーヤーがオンラインで同時にセッションをプレイし、ユニットの借用、ユニットの取引、リーダーボードなどのソーシャル メカニクスがプレーヤー間の唯一のコンタクト ポイントとなっています。MASS ゲームの例には、パズル&ドラゴンズ™、モンスターストライク™ があります。MASS モバイルゲームは、クライアント / サーバー コミュニケーションで経済的に作成されています。これにより、ユーザーは、限定された、または散発的な接続性の場合であってもゲームを楽しむことができます。このようなゲームのデータモデルでは、ほとんどすべての永続状態ストレージがメタゲーム(ユニットを収集し、プレーヤーの通貨を維持管理)に関連しており、データベースに格納する 2 つの基本的なオブジェクト タイプが生成されます。これらのオブジェクトは、CRUD メカニズムを使用して簡単に操作できます。

プレーヤー オブジェクトは、以下を追跡します。

  • ゲームと実通貨。
  • ユニット在庫スロットの合計数。
  • スタミナ。
  • 経験値。

ユニット オブジェクトは、以下を追跡します。

  • 所有者(プレーヤー ID)。
  • 経験値。
  • 獲得する費用。
  • ユニット在庫。

100,000 名未満のプレーヤーの場合、このデータモデルは、Cloud SQL 第 2 世代などのリレーショナル データベースによく適合しています。

Mimus

Mimus は、パズル&ドラゴンズ™ やモンスターストライク™ のスタイルのバックエンドを備えたモック MASS モバイルゲーム アプリケーションです。各プレーヤーは、一度に 1 つのデバイスからのみログイン可能で、別の操作を始める前にすべての操作を完了しなければならないのが前提です。Mimus では、シミュレートされたワークロードを実行して、アーキテクチャの最適な容量を評価できますが、これは一般に同時ユーザー数(CCU)に基づいています。

Mimus のソースコードは https://github.com/GoogleCloudPlatform/mimus-game-simulator にあります。

Mimus アーキテクチャの概要

Mimus サーバー内での Mimus クライアント シミュレーション

MASS ゲームでは、クライアントがデータベース クエリを生成するレートは、ゲーム デベロッパーがプレーヤーにアニメーションを表示するよう要求すること、またゲーム クライアントとやり取りして続行するように要求することにより制御できます。Mimus は、これらのレートを制限する戦略を sleep() 呼び出しでシミュレートします。この方法で、Mimus は、シミュレートされたプレーヤーと同じ数のプロセスを実行することにより、クライアント データベースごとの負荷の合理的な概算値をシミュレートします。これは、Kubernetes クラスタ内でデータベースに対してクエリを生成するコンテナ化された Mimus クライアント / サーバーポッドを使用して効率的に調整されます。

Mimus ゲーム クライアントは、Mimus サーバー プロシージャを直接呼び出す継続的なループを使用し、プレーヤーとその在庫の状態に基づいて関数呼び出しを選択することにより、バックエンド サーバーとのコミュニケーションをシミュレートします。

Mimus によってシミュレートされる操作には、次のものがあります。

  • ゲームを 1 ラウンドだけプレイ。
  • 通貨を購入。
  • 通貨を使用。
  • ユニットのレベルアップや進化。

これらの各操作は、プレーヤーまたはユニット オブジェクトとの複数の CRUD インタラクションとして実装され、Mimus サーバーの呼び出しを通してクライアントによって操作されます。Mimus サーバーは、同期(ブロック化)Mimus データベース API を使用して、これらのデータベース リクエストを行います。この API は、Mimus サーバーによってインポートされた Python モジュールであり、さまざまなデータベース バックエンドの実装をテストするように構成できます。

Mimus データベース ワーカープールと Mimus データベース API のコミュニケーション

以下の図は、Mimus サーバーとデータベース サービスのコミュニケーションを示しています。

Mimus のコミュニケーション設計

Mimus データベース API は、データベース クエリのバッチを受け取り、結果を返します。これらのバッチを Cloud Pub/Sub メッセージとして公開し、結果が Redis を通して返されるのを待ちます。メッセージを送信する前に、データベース API は、データベースに書き込まれるすべての値を検証し、一意の取引 ID でメッセージにタグ付けします。次に、メッセージは Cloud Pub/Sub 内の Work トピックに公開されます。次に、データベース API がループし、Redis キーとして取引 ID が存在するかポーリングします。次に、キー値内の結果がデータベース API によって取り出され、Mimus サーバーに返されて、そこから Mimus クライアントによって使用できるようになります。

コミュニケーションの選択に関する考慮事項

ユーザーの操作では耐久性および信頼できる配信が必要となるため、Mimus は、保留中のクエリ コミュニケーション用に Cloud Pub/Sub を使用します。Mimus は、耐久性と信頼性の重要度が低い場合、Redis を使用して結果を通信します。アプリケーション エラーまたは Redis の障害により結果が失われた場合、Mimus Client は、最終的な結果をもう一度データベースにクエリします。リレーショナル データベース内のトランザクションを使用することにより、要求されたすべての変更が実施されたか、またはまったく実施されなかったことが保証されます。まれな場合として、Mimus が 2 番目のリクエストを作成する必要がある場合は、Redis によって提供される取り出しの簡潔性と速度に対する容認可能なトレードオフと考えられます。Redis の使用を合理的に保つため、リクエストの結果は 30 秒後に Redis から期限切れにすることができます。

Mimus データベース ワーカープール

Mimus データベース ワーカープールには、Kubernetes Engine で動作する複数のプロセスが含まれます。実行中の各コンテナ インスタンスは、無限ループ内で Work Cloud Pub/Sub トピックにポーリングして、新しいメッセージを確認します。メッセージを受信すると、Python MySQLdb モジュールを使用してメッセージ内でクエリを実行します。単一のメッセージは、リレーショナル トランザクションを表し、複数のクエリを含むことができます。メッセージ内のすべてのクエリは、データベースに commit される前に完了する必要があります。クエリが完了(または失敗)した後、データベース ワーカーは、元のメッセージの一部として受信した取引 ID で、結果を Redis に公開します。

Mimus データベース

Mimus データベース サービスの背後にあるリレーショナル データベースは、Cloud SQL for MySQL 第 2 世代のインスタンスです。インスタンスを作成時に、最大 32 コアおよび 208 GB の RAM を備え、最大 10 TB のディスクサイズを持つマシン構成を選択できます。さらに、レプリカのサポートに加えて、Cloud SQL 第 2 世代のインスタンスは、デフォルトで定期バックアップを実行するように構成できます。さらに MySQL のチューニングが必要な場合、Cloud SQL インスタンスに特定の MySQL フラグを設定できます。構成に関するさらに詳細な情報が、Cloud SQL ドキュメントにあります。

Mimus を使用した Cloud SQL のテストからの結論

Cloud SQL SG マシンタイプ 推奨される同時ユーザー数
n1-standard-4 15,000
n1-standard-8 30,000
n1-standard-16 60,000
n1-standard-32 120,000
n1-highmem-8 50,000
n1-highmem-16 100,000
n1-highmem-32 200,000

Mimus テストを活用して、n1-highmem-16 Compute Engine インスタンス上で作成された Cloud SQL for MySQL 第 2 世代インスタンスに対して 100,000 人の同時ユーザーをシミュレートすると、クエリ応答時間はテスト全体を通して 2 秒未満に収まりました。

MASS モバイルゲームを作成していて、数十万の同時プレーヤーをサポートする必要がある場合、Cloud SQL for MySQL 第 2 世代に基づくサービス フロント データベース パターンによって、必要なパフォーマンスを提供できます。ゲームが広く使用されるようになった場合、追加の Cloud SQL インスタンスを分割またはレプリカとして導入して、データベース サービスレベルの Redis または Memcached キャッシュ戦略によって、パフォーマンスを容認可能なレベルに保つことができます。

もっと少数の同時ユーザーが予想されるゲームでは、より小さなマシンタイプを使用して費用を削減できます。

予想される CCU が数百万のゲームの場合、Google Cloud Datastore や Google Cloud Bigtable など、強力なスケーラビリティとパフォーマンス特性を持つ NoSQL データベースを検討する必要があります。

次のステップ