LoadBalancingアプリケーション

本稿では、サーバー側のロードバランサーアプリケーションの実行について説明いたします。

目次

コンセプト

Photon3では、ロードバランサーアプリケーションは(文字通り) Lite アプリケーションを拡張するものです。 標準の Lite 機能- Rooms 、イベント、プロパティなど-に、多数のサーバーでアプリケーションの実行を可能にするスケーラビリティレイヤーが加えられました。ロードバランシングはロビーサポートとマッチメイキングの機能も与えます。Photon4ではLiteは非推奨となりHiveに変わりました。そのため現在ロードバランシングは複雑だけど拡張性の高いHiveの拡張となっています。

基本設定はとても簡単です: 常に1つのマスターサーバーに数台のゲームサーバーが繋がっているシンプルな構成です。

Photon Server Concept: LoadBalancing Setup

マスターサーバーは次のタスクを実行いたします:

  • ゲームサーバーで開戦中の対戦を記録。
  • 接続されているゲームサーバーの負荷を記録、および peer に適したゲームサーバーをアサイン。
  • 「Lobby」(ロビー)内のクライアントに対して、使用可能な room のリストを維持、アップデート。
  • クライアントに対して、 room をアサイン(ランダムまたはネーム指定)およびゲームサーバーアドレスを転送。

ゲームサーバーは次のタスクを実行いたします:

  • 対戦 room のホスティング。そのためには少し変更を加えたバージョンの Lite Applicationが実行されています。
  • マスターサーバーにそれぞれの最新の負荷や対戦リストを定期的にレポート。

Photon Cloudとの違い

ロードバランサーアプリケーションは Photon Cloudサービスとほぼ同じロジックを提供しています。 Cloud サービスとして作動するために必要だがカスタムロジックの特別なサーバーに応用できない要件は取り除かれました。これによりコードはかなりシンプルになりました。

  • 仮想アプリケーションはありません。1つの LB インスタンスに対して1つだけの対戦ロジックが実行されます。 Authorize 作動中のアプリケーション ID は無視されます。
  • 「game version」(対戦バージョン)パラメータでのプレイヤー識別はありません。これは仮想アプリの一部です。

Back to Content

基本ワークフロー

クライアント側の観点からのワークフローも大変シンプルです:

クライアントはマスターサーバーに接続し、ロビーに入り、開戦中の対戦のリストを読み出します。

マスターの CreateGame 操作を呼び出す時、対戦は実際には作成されません-マスターサーバーはあくまで負荷の一番少ないゲームサーバーを特定し、その IP をクライアントに返すだけです。

クライアントがマスターで JoinGame 或いは JoinRandomGame の操作を呼び出す時、マスターは対戦が実行されているゲームサーバーを調べ、その IP をクライアントに返します。

クライアントはマスターサーバーとの接続を切り、受信した IP でゲームサーバーに接続して再び CreateGame または JoinGame の操作を呼び出します。

ここからは全て Lite Applicationと同じように行われます。

Photon Server: LoadBalancing Flowchart

Back to Content

マスターサーバー

ここではマスターサーバーの実行について説明します- \src-server\Loadbalancing\Loadbalancing.sln ファイルの LoadBalancing.MasterServer namespace をご覧ください。

MasterApplicationは、受信接続の発信元がゲームクライアント(「client port」(クライアントポート))なのか、ゲームサーバー(「game server port」(ゲームサーバーポート))なのかを判断します。

マスター: クライアント Peer の処理

MasterClientPeerはマスターサーバーへのクライアント接続を現わしています。 MasterClientPeer での操作は以下の通りです:

  • 認証
    認証 操作にはダミー実行しかありません。これは開発者が独自の認証メカニズムを実行する際、出発点として利用するためのものです。
  • JoinLobby JoinLobby 操作は、 MasterClientPeer を、 GameList が含まれている AppLobby に追加するために使われます- GameList には全てのゲームサーバーで開戦されている対戦が含まれています。 Peer は GameList にある最新の対戦リストが含まれている初期の GameListEvent を受信します。( GameList は JoinLobby 操作のオプショナルプロパティでフィルタリングした状態です): その後、変更された対戦のリストを含む(これもJoinLobby操作のオプショナルプロパティでフィルタリングした状態です) GameListUpdateEvent が一定の間隔でクライアントに送信されます。クライアントは接続されている間、アップデートイベントを受信し続けます。

    その後、変更された対戦のリストを含む(これも JoinLobby 操作のオプショナルプロパティでフィルタリングした状態です) GameListUpdateEvent が一定の間隔でクライアントに送信されます。 クライアントは接続されている間、アップデートイベントを受信し続けます。

  • JoinGame / JoinRandomGame
    JoinGame 操作は、 AppLobby の GameList にある、固有の GameId で特定される既存の対戦に、クライアントが参加したい時に呼び出されます。 対戦が存在し、 peer がそれに参加することを許可されている場合、マスターサーバーは対戦が実際に実行されているゲームサーバーの IP をクライアントに返します。

    マスターサーバーは GameSate をアップデートし、 peer をサーバー内の「joining peers」リストに加えます。ゲームサーバー上の対戦に参加した時(またはある程度のタイムアウトにより) peer はそこから削除されます。 このようにマスターサーバーはマスターとゲームサーバーの間を移行する peer を記録します。

    JoinRandomGame は同じように作動しますが、この場合マスターサーバーは、対戦をランダムに選んで GameId をクライアントに返します。

  • CreateGame
    CreateGame 操作は、クライアントが新しい対戦を作りたい時に呼び出されます。 マスターサーバーは、新しい対戦が作成されるゲームサーバーを特定し、ゲームサーバーの IP をクライアントに返します。詳細は以下の「ロードバランサーアルゴリズム」をご覧ください。

    さらに、 GameState オブジェクトが作成されて、 GameList に加えられ、 peer は「joining peer」として記録されます。
    GameStateはあくまで対戦を記録するためだけにあります-対戦そのものはゲームサーバー上でのみ存在するものです。

Back to Content

マスター: ゲームサーバー Peer の処理

マスターサーバーは、どのゲームサーバーが利用可能なのか、これらがいくつの対戦をホスティングしているのか、そして最新の負荷などの情報を常に持っています。

そのためには、各ゲームサーバーが起動時にマスターサーバーに接続します。 MasterApplication が、 IncomingGameServerPeers が記憶されている GameServerCollection を維持しています。

ゲームサーバーは1つの操作のみ呼び出すことができます:

  • RegisterGameServer
    ゲームサーバーはマスターサーバーに接続した後、 RegisterGameServer 操作を呼び出します。 ゲームサーバーはマスターの GameServerCollection と LoadBalancer (以下の「ロードバランサーアルゴリズム」を参照) に追加されます。 Disconnect 操作で GameServerCollection から削除されます。

    ゲームサーバーがどのように自分の対戦や負荷をマスターに送信しているかについては以下「ゲームサーバー」の項目をご覧ください。

Back to Content

ゲームサーバー

ここではゲームサーバーの実行について説明いたします。\src-server\Loadbalancing\Loadbalancing.sln ファイルの LoadBalancing.GameServer namespace をご覧ください。

ゲームサーバー: クライアントPeerの処理

ゲームサーバーは Lite Application から派生します。 クライアントがマスターからゲームサーバーアドレスを受信した時点で、クライアントは Lite で利用可能なゲームサーバーで、どの操作でも呼び出すことができます。 唯一違うのは、ゲームサーバーでは JoinGameCreateGame 操作に別々の操作コードが使われているのに対し、 Lite は両方ともに JoinGame 操作で処理しているということです。

Back to Content

ゲームサーバー: マスターにゲームステートを報告

ゲームサーバーでは、マスターサーバーとの接続は OutgoingMasterServerPeer として現れます。 接続が完了した時点で、ゲームサーバーはマスターサーバーで Register 操作を呼び出します。 その後、ゲームサーバーは既存の対戦ステートを全て、マスターサーバーに公開します。

これは、各 room に、対戦ステートをマスターに送るようメッセージを送信して、実行されます。

Room はこれを ProcessMessage メソッドで処理し、 UpdateGameStateOnMaster メソッドを呼び出して、マスターに UpdateGameEvent を送信します。:

新しい対戦が作成された時、クライアントがroomに入室/退室した時、そしてroomのプロパティが変更された時にも、対戦ステートはマスター側でアップデートされます。

Back to Content

ロードバランサーの実行

次の項目では、ゲームサーバーがどのように自分の負荷に関する情報をサーバーにレポートしているのか、マスターサーバーがどのように新しい CreateGame リクエストに相応しいゲームサーバーを特定しているのか-実際のロードバランサーアルゴリズムについて説明します。

Back to Content

ゲームサーバー: 負荷の特定

実行の詳細については \src-server\Loadbalancing\Loadbalancing.sln ファイルの LoadBalancing.LoadShedding namespace をご覧ください。

ゲームサーバーは、自身の負荷について最新の情報を定期的にマスターサーバーにレポートしています。負荷の情報には例えば、次のような情報が含まれています:- CPU 使用率-バンド幅使用率-ENet + Business Queue Length、サーバーが各リクエストに費やす平均時間などの Photon 独特の値-(自分にリクエストを送信した時の)レイテンシー。:

もっとも重要な(そして一番分かりやすい)ファクターは CPU の負荷なので、ここでは CPU の負荷に焦点を当てて説明いたします。

これら全てのファクターは一つの値-ゲームサーバーの「Load Level」(ロードレベル)に集約され、マスターサーバーにレポートされます。

ロードレベルが低ければ低いほど、ゲームサーバーは新しい対戦をホスティングしやすくなります。

Back to Content

実行に関する詳細

ゲームサーバーは上記ファクターについて「Feedback」(フィードバック) を収集します。各ファクターには1つの FeedbackController オブジェクトがあります- FeedbackName と FeedbackLevel で構成されています:

DefaultConfiguration クラスはそれぞれの値の閾値を定義しています- 例えば20%までの CPU 使用率ならサーバーの FeedbackLevel は「lowest」と判定され、 90%までなら FeedbackLevel は「highest」と判定される、などなど。

これらの値は workload.config fileファイル でも設定することができます。 LoadBalancing.LoadShedding.Configuration namespaces が config file から値を読み込む役割を果たし、または configファイル が存在しない場合は、 DefaultConfiguration を適用します。

一定の間隔でゲームサーバーは Windows Performance Counters を一部チェックし、自分の全ての FeedbackControllers の最新値を設定して、新しい「overall feedback」(全体フィードバック)を計算します。

これは WorkloadController クラスで実行されます:

全体のフィードバックレベルに変更があった場合、 OutgoingMasterServerPeer がマスターに新しいサーバーのステートをレポートします。

Back to Content

マスターサーバー: ロードバランサーアルゴリズム

実行の詳細については \src-server\Loadbalancing\Loadbalancing.sln ファイルの LoadBalancing.LoadBalancer クラスをご覧ください。

マスターサーバーは各ゲームサーバーの LoadLevel を、 LoadBalancer クラスに記憶しています。 また、最新のロードレベルが lowest であるサーバーのリストも、別にもっています。

クライアントが CreateGame 操作を呼び出す度に、マスターサーバーは LoadBalancer から、ロードレベルが lowest であるサーバーのアドレスをフェッチし、それをクライアントに返します;クライアントはそのアドレスでゲームサーバーに接続します。

Back to Content

コンフィギュレーションとデプロイメント

デモとして SDK には、デプロイディレクトリに1つのマスターサーバーと2つのゲームサーバーのセットアップが含まれています:

  • /deploy/LoadBalancing/Master
  • /deploy/LoadBalancing/GameServer1
  • /deploy/LoadBalancing/GameServer2

このセットアップはローカル開発のみを目的としています。

ゲームサーバーのデプロイメント

LoadBalancing プロジェクトをプロダクションサーバーにデプロイする時は、1つのサーバーに2つのゲームサーバーアプリケーションをホスティングしてはなりません。 PhotonServer.config から「GameServer2」の全ての設定を取り消し、 /deploy/LoadBalancing/GameServer2 ディレクトリを削除してください。

ゲームサーバーがマスターサーバーに確実に登録できることを確認する必要があります。 Photon.LoadBalancing.dll.config にある MasterIPAddress をマスターのパブリック IP に設定してください。

また、対戦クライアントが確実にゲームサーバーに辿りつけることを確認してください。それぞれのゲームサーバのパブリック IP アドレスを設定してください。 値を empty (空)のままにしますと、パブリック IP アドレスは自動的に検知されてしまいます。

パブリックIP の設定に Photon Control を使うこともできます。

マスターサーバーのデプロイメント

マスタサーバが一つであることを確認してください:ゲームサーバのPhotonServer.configから"Master"アプリケーションの全ての設定を取り除くか、ゲームサーバと全てのクライアントが同じIPで一つのマスタサーバに接続していることを確認。

それ以外はマスタサーバ上で必要な特別な設定はありません。

目次に戻る

Game Serverのローテーションを止める

目次に戻る

"[Loadbalancing] (lbilb)"項目で説明したとおり、マスタサーバはゲームサーバの状態を"ServerState" の値から認識します。

  • "online" (デフォルトです)
  • "out of rotation(ローテーションを止める)" (オープンなゲームはロビーに表示されプレイヤーはサーバ上の既存ゲームに参加できますが、新規ゲームは作成されません)
  • "offline" (サーバ上の既存ゲームに参加できず、ゲームサーバ上に新規ゲームの作成も出来ません)

ゲームサーバは定期的に状態をマスタに送信します。OutgoingMasterServerPeerクラスを参照:

サーバの状態をプログラムで設定したい場合、次のように行います:

  • WorkloadControllerクラスを修正して現在のサーバの状態を判断させます。

  • 例えば、"file watcher"を追加してテキストファイル(0 / 1 / 2)からサーバ状態を読むようにします。

クライアントやデータベースから呼ぶオペレーションを構築することもできます。

 ドキュメントのトップへ戻る