<h1>最近構築したスマホゲームのサーバーの話</h1>
これは、少し前に開発/運用していたスマホゲームのサーバー構成です。 大きく5つのブロックに分けています。
[peg-image src="https://lh3.googleusercontent.com/-9pYT3oOxQi0/VvIxO4SIarI/AAAAAAAAHvQ/Rnv3xEmDVyc9FAgD9N39qGtaOV8hzvNrwCHM/s144-o/system_map_2015.png" href="https://picasaweb.google.com/101465714064559237741/iJepED#6265124163322145458" caption="" type="image" alt="system_map_2015.png" image_size="1618x893" ]
- Contents 画像やパッチを配信するサーバー群。
- Application ゲームの中枢。WebAPIのためのサーバー群。 ゲームロジックはほとんどここに置いてあります。
- Socket リアルタイムマルチプレイのためのサーバー群。
- Tool 管理者がなにかしら操作したり、KPIを見たりするためのサーバー群。
- その他
Contents
画像やパッチを配信するサーバー群です。
https://contents.tnnsst35.me/1.00.00/assets/hogehoge https://contents.tnnsst35.me/1.01.00/assets/hogehoge
上記のように、Versionごとに管理、配信するようにしています。 実際にはCDNでキャッシュを返しています。
Application
ゲームの中枢。WebAPIのためのサーバー群です。
ほぼ全てのデータはMySQLに格納しており、Redisのデータ型を上手く利用できる一部のデータだけをRedisに格納しています。
MySQLのデータは、データの用途に対していくつかのグループをつくり、グループごとにデータベースを作成しています(機能による垂直分割)。 とある要因で水平分割はしていませんが、将来的にできるような想定でアプリケーション側を構築しています。
MySQLアクセスによる負荷の軽減のために、Tomcatサーバーのヒープメモリ上に、MySQLのマスタデータを一部キャッシュしています。 キャッシュタイミングはTomcat起動時で、MySQLのマスタデータが切り替わる時に、Tomcatを再起動してあげる必要があります。 ダウンタイムなしにアップデートが可能で、サーバー間によるキャッシュデータの差異をなくすために、ホットスタンバイさせているTomcatを先に再起動/最新データをキャッシュさせ、Proxyでアクセス先を変更しています。
残念ながらApplicationサーバーは、最新のVersionのみしか管理、配信できていないので、ゲームアップデート時にメンテナンスが高確率で必要など課題を残しています。
Applicationサーバー群のパフォーマンステストには、JMeterを利用しています。
Socket
リアルタイムマルチプレイのためのサーバー群です。 Node.js + socket.ioで、セッションストア兼リレーサーバーにはRedisを採用しています。 Node.jsのマルチスレッド対応にはPM2モジュールを利用しています。
Socketサーバー群のパフォーマンステストには、自作クライアントを利用しています。
Tool
管理者がなにかしら操作したり、KPIを見たりするためのサーバー群です。 実際には、ランキング集計バッチなんかも動作させています。
その他
その他に置いているサーバー群です。 Deployは、DeployサーバーのユーザーがSubversionからリソースを取得し、Contents、Application、Socket、Toolの各サーバーにrsyncで配布します。
通信ルール
クライアントとサーバーの通信には以下のルールを適応しています。
- サーバーからのレスポンスはJSON形式。
- サーバーからクライアントへのレスポンスに、最新クライアントVersionを付加するので、今のクライアントVersionと比較して古ければストアに飛ばす。
- サーバーからクライアントへのレスポンスに、最新パッチVersionを付加するので、今のパッチVersionと比較して古ければ(タイトルから遷移するときにパッチ適応させるため)タイトルに飛ばす。
- サーバーがメンテナンスの場合は、メンテナンスコードをレスポンスに含めるので、クライアントでメンテナンス表示にする。
まとめ
「ユーザーがいっぱい来たらお金をかけてがんばりましょう」というのが方針なので派手なことはしていませんが、最低限の冗長化と負荷対策、スケールアウトできる構成にしています。 残念ながら悲鳴をあげるほどゲームが流行らなかったのですが・・・。
Redis、Socketサーバー群の各ミドルウェアの採用は私が決めましたが、それ以外は前任者から引き継いだものをより柔軟に対応できるように構成を再構築したものです。