Edited at

Nianticの求人から推測する『Pokémon GO(ポケモンGO)』のサーバ構成

More than 1 year has passed since last update.


この文章の目的

『Pokémon GO』(以下ポケモンGO)1が人気だ。リリースから数ヶ月が経過したが、未だに根強い人気があり、むしろどんどん人気に火がついているように見える。この文章ではその人気のポケモンGOのサーバはどういう構成になっているかをこのゲームを開発したNianticの求人ページから類推する。そして、結果として日本のオンラインゲームの作り方に大きな変更が起こるかも知れないことを指摘する。

使用した求人はサイトは こちら2


ポケモンGOのサーバ構成

求人からわかるポケモンGOのサーバ構成(以下求人情報を元に推測した結果なので間違っている可能性があることは承知しておいて欲しい)。

項目
使用技術

データストレージ
NoSQL(BigtableDatastoreどちらか)

クラウドサービス
Google Cloud Platform

サーバコンテナーエンジン

Docker and Kubernetes

使用言語(サーバサイド)
java(ポケモンGOなのにGO言語じゃないなんて・・)

使用言語(クライアントサイド)
java,C++,C#(unity)

ワールド分割
なし(1ワールド)


判断根拠

上記リストの判断根拠は以下の、


データストレージ

Software Engineer - Server Infrastructureの


key skill Java, Cloud Computing, NoSQL


よりGoogle Cloud Platformが提供している Bigtable か Datastoreを使っているだろうと考えた。GoogleのCloud SQLはRDBMSなので、除外。また、GCP上で大量のインスタンスを立てて、自前でHBaseなどのNoSQLを運用するやり方もあるが、そうするとユーザーの伸びに対処できないので、BigtableかDatastoreを使っていると考えるのが自然だろう。HBaseなどを立てて自前でクラスターを構成する場合、自由度は上がるが全ての管理を自前でしなければならない。社員数の少ないベンチャーのNianticがそれをやっているとはあまり思えない。


クラウドサービス

Software Engineer - Server Infrastructure の 説明文


Pokémon GO using Java and Google Cloud.


より。Google Cloud PlatformのCompute Engineを使っている。


サーバコンテナーエンジン

Production Engineer / DevOps / SRE の説明文


server releases on Google Container Engine using docker and kubernetes.


より、DockerとKubernetesを使ってる。


使用言語(サーバサイド)

Software Engineer - Server Infrastructureの


key skill Java, Cloud Computing, NoSQL


や他の箇所に見られるようにjavaを使っている。GO言語では無いようだ(しつこい)。


使用言語(クライアントサイド)

Mobile Software Engineer の


Key Skills: Java, C++, Android or iOS, Mobile application development


及び Unity Game Developer の


Key Skills: Unity3D (Unity 3D), C#


より、java,C++,C#が使われている。ゲーム開発の環境としてUnityが使われている。


ワールド分割

これは要素技術というよりは、設計アーキテクチャーの話だが、後半重要になるので一緒にあげている。

Software Engineer - Server Infrastructureでの次の説明


all on a single, coherent world-wide instance shared by millions of users.


との説明より、1ワールドで運用している。


一般的なMMOでの構成技術との比較

求人表中に、MMO3の経験という言葉が何度も出て来る。表を上げてみても、使われている技術としては、MMOとの関連が深そうだ。

項目
ポケモンGO
一般的なMMO

クラウドサービス
Google Cloud Platform
バラバラ、自前で購入することも多い

データストレージ
NoSQL(bigtable,data storeどちらか)
RDBMS(MySQL,PostgreSQL,Oracle)

サーバコンテナーエンジン
docker and kubernetes
使わない事が多い4

使用言語(サーバサイド)
java
java,c++あたりが標準的

使用言語(クライアントサイド)
java,C++,C#(unity)
java,c++,C#あたりが標準的

ワールド分割
なし(1ワールド)
1ワールド、人気が出たらワールドを分けることが多い


1ワールドで済ますというチャレンジ

Nianticの求人を見ていて、凄く驚いたのは、「Software Engineer - Server Infrastructure」での次の項目。


 all on a single, coherent world-wide instance shared by millions of users.


対訳


全ての(アクション)は、数百万のユーザーに共有された単一の一貫した(サーバ群で行われる)


つまり、ポケモンGOは1ワールドで構成されている。MMOのサーバを作ったことがある人なら5それがどんなに大変かピンとくるだろう。特に、ポケモンGOの様に一日に数百万人とかが遊ぶゲームで、1ワールドでゲーム世界を構築するのは、結構大変だ。6


MMOで1ワールドがなぜ大変か(データストレージとの戦い)

MMOの様なオンラインゲームで、1ワールドがなぜ大変かを図示する。

simple MMO.png

通常のオンラインゲームの場合、次のような構成を取る。ユーザー何百、何千、何万人か単位でゲームサーバを複数台使う。そして、データベースサーバは通常一台だ。ゲームサーバは、永続的なユーザーデータを持たない(一回のログイン時間ぐらいしか保持しない)ため、ユーザーが増えたときに台数を増やすことは容易だ。しかし、データベースはそうではないので、ユーザーが増えたときは、ワールド毎に分割する。この方式であれば、データベースがボトルネックになる前にワールドを分割するため負荷の問題が起こりにくい。ワールドのサイズをデータベースの性能以下に抑えれば、負荷の問題は起こりにくくなる。しかしこの方法には欠点がある。例えば友達と同じワールドで遊ぼうと思っても、ゲームユーザーの時期の違いなどで一緒に遊べない。艦これの鎮守府が違えば、同じランキングに乗らないのと一緒の原理だと考えるとわかりやすい。

parallel_mmo.png

MMOの場合、ゲームサーバは、負荷に応じてマシンの増減ができるので負荷分散は可能だが、1つのワールドに1つのDBしか置けないので、負荷分散は容易ではない(後述するように、レプリケーション、垂直分割、水平分割などの手はある)。つまり、データベースの性能がボトルネックになって、ワールドを分割せざるを得ないのだ。特に、MMOでは、webサービスに比べてデータの書き込みが多く発生するためDBへの書き込み性能がボトルネックになる。また、ユーザーの増加も厄介な問題だ。一人二人なら問題なく動いていても、それが100万人、1000万人に増えると、保存するデータの量が膨大になりすぎて性能が全然出なくなる。


レコードの保存量が増えるにしたがって性能が劣化する。

MySQLなどのオープンソースのRDBMSを使った場合、レコードの保存量が増えれば増えるほど、いろいろなことに神経を使わなければならなくなる。下記資料は、MySQLを使って、2億件のデータをインサートした話だが、件数が増えるにしたがって、インサートの時間が伸びたりと色々とチューニングに手間を費やしている。

http://www.slideshare.net/saiken3110/my-sql2

MySQLで数億件のレコードが扱えないわけではないが、数千万の段階で色々とチューニングが必要になるし(億になったら更に)、データ自体の取扱に非常に神経を使う。


レプリケーションではなぜだめか

レプリケーションとは、DBの内容を同期させることで、DBを複数台にわけ、負荷を分散するやり方だ。webサービスのように、データの読み込みが主で、書き込みが相対的に少ないサービスであれば、それでも問題ない。しかし、レプリケーションは弱点があり、読み込みが複数台に分散できるが、書き込みはマスターデータベースという一台しか使えず、そのためデータの書き込みは、複数台にわけられないのだ。

下記の図中、黒の線は読み込みで、それぞれ分割したデータベースから読んでいる。しかし、赤い線は書き込みで、一つのデータベースに集中している。

MMOはデータの書き込みが読み込みと同程度発生する(アイテムを取得した、チャットした、クエストに勝った、経験値がアップした等々、イベントが発生するたびにそのデータを保存する必要がある。当然、ポケモンをゲットしてもそれを保存する必要がある)。その為、レプリケーションを行っても、読み込みは複数台に分散できるが、書き込みは一台に集中するために、分散出来ない。

レプリケーション.png


DB分割(垂直、水平)

その他の手法に、垂直分割や水平分割がある。垂直分割はアイテムやユーザー情報などを違う役割のテーブルを別々のDBに保存する方法。水平分割はユーザーIDに基づいて保存するDBを切り替える方法。それぞれDBを一台では無く複数台に分けられるため、負荷を分散出来て、性能の劣化を起こしにくい。しかし、増えたDBの台数や接続するDBなどをプログラム上で管理する必要があるため、開発は楽とは言えない。


その他の分散技術

MySQLであれば、MySQL Clusterを使うとか、MySQL Proxyを使って、DBを分散する方法はあると思うが、試したことがないので詳しいことは分からない。


1ワールドが難しい理由

上記に見たように、MMOで1ワールドを維持するのは、大変だ。主に、データベースのようなデータストレージがボトルネックになりやすい。データストレージがボトルネックになるのは以下の2つが大きな要因だ。


  1. そもそもあまりに大量のデータを入れるとオープンソースのRDBMSは性能が劣化する。

  2. MMOは書き込みが多い。


1ワールドを維持するために、GoogleのBigTableやDataStoreを使う

Nianticのチャレンジの面白いところは、1ワールドを維持するために、BigTableやDataStoreなどのGoogleのNoSQLを使い、仮想的にデータの保存処理をシンプルにしているところだ。図示すると以下のようになる。

NoSQL (1).png

BigTableにしろ、DataStoreにしろ、後ろ側ではデータを分散して保存しているにも関わらず、ゲームの開発者から見たらあたかも一台のマシンにアクセスしているような感覚で使える。図のように開発者から一台のマシンにデータを読んだり書いたりしているように見えて、実際は複数台のマシンに分割してデータを読み書きしている。

その為、保存データが1件だろうが、1億件だろうが、読み書きの時間は長くならない7。 データ更新の時間は早いわけではない8が、データの保存件数が増えたからと言って極端に遅くなるわけでも無い。

その為、ユーザーが増えてもデータストレージの性能劣化が起こりにくい。しかも、ポケモンGOの様な大ヒットタイトルで、各国のスマホアプリストアランキング1位を獲得するほど、ユーザーを獲得しながら、それでも1ワールドを維持できるほど、性能がスケールすることが明らかになった。


まとめ1 ポケモンGOのサーバ構成

上にあげたように、ポケモンGOを作るにあたって、Nianticは、GoogleのGoogle Cloud Platformを利用している。Google Cloud Platformを利用することで、爆発的なユーザー数の増加に効率的に対処している。Googleの技術を使わなければ、これほどスケールすることは難しかったのではないか。


まとめ2、1ワールドを維持するために、BigTableやDataStoreを使うゲーム会社が現れるかも

今まで、伝統的なMMOの作り方は、RDBMSなどを使ったパラレルワールドの作り方が一般的だった。しかしこれからは、Google BigtableやDataStore、AWSのDynamoDBなどを使ったゲーム開発も広がるかも知れない。

上の例で見たように、パラレルワールドはゲームデザインによる要望というよりもゲームサーバによる制約で、それがなければ、1ワールドで遊べたのに、複数ワールドで遊ぶ遊び方になっている。その制約を取り払い、1ワールドで遊ぶために、BigTableやDataStoreなどを使うゲーム会社が現れるかも知れない。今までも、BigTableやDataStoreやその他NoSQLを使い、1ワールドでオンラインゲーム作ろうという話はあったが、あまり実例も無く、夢物語として扱われることも多かった。

しかし、ポケモンGOの成功を受けて、夢物語ではなく実際にBigTableやDataStoreなどを使ってゲームを作れることが証明されてしまった(しかも、これほどの大ヒットにも関わらずサービスを継続出来るなど、異常にスケールすることも証明してしまった)。この成功を受けて、BigTableやDataStoreなどをデータ保持に使う企業が現れるかも知れない。

下の例が示すように、今まで慣れ親しんできたRDBMSでのモデル設計と異なる部分も多いため、実際には適材適所で使われることになるだろう。


一応補足

上の項目では、NoSQLのスケーリングばかりを取り上げているが実際に、ゲームデータを保存したり参照したりする際に、考慮しなきゃならない問題を挙げておこう。代表的な話は、RDBMSには備わっているトランザクションとjoinの話だ。


DataStoreにはトランザクションもある

時々 NoSQLにはトランザクションは無いみたいな話を聞いたことあるが、トランザクションのあるNoSQLもある。DataStoreは対応しているようだ。トランザクション分離レベルとしてはどうかみたいな話は、まだちゃんと読めてないので、今後、色々試行錯誤して明らかになっていくだろう。

https://cloud.google.com/datastore/docs/concepts/transactions


Joinは無い

joinは無い様なので、MySQLと同じような使い方は難しいだろう。わざと非正規化などを行わないといけないかも知れない。

パフォーマンスの話は、以下の記事に詳しい。

https://thinkit.co.jp/story/2015/02/05/5594


番外編(お金で解決)

上に書いたようなオープンソースのRDBMSを使ったり、GoogleのNoSQLを使う以外にお金を払って1ワールドを実現するやり方がある。スクウェア・エニックスがドラゴンクエストⅩで採用したOracle ExaDataを使うやり方がそれだ。

「ドラゴンクエストXは「世界は一つ」を実現するためにどのようなサーバ構成にしているのか?」

http://gigazine.net/news/20120824-dragonquest-backstage-cedec2012/

「 スクウェア・エニックス、オンラインゲームのIT基盤にOracle Exadata を導入」

http://www.oracle.com/jp/corporate/features/square-enix-exadata-1906860-ja.html

MySQLなどを利用してチューニングが面倒な場合には、Oracle Exadataを買ってしまうというのも手だ。Cedecの講演にもあるように、事前に十分テストをすれば、チューニングにもそこまで悩まなくても良いようだ。とはいえ、多少値が張る2390万円(ハードウェア最小構成、税抜)ので、そう簡単に導入したいですとは言いづらい。ドラクエのナンバリングタイトルなら人が来るのは分かっているのでチャレンジできたのかも知れない。


参考書籍

オンラインゲームを支える技術  --壮大なプレイ空間の舞台裏 (WEB+DB PRESS plus)

オンラインゲームの開発における教科書の様な存在。2011年出版とは言え未だに内容は古びていない。情報をアップデートするとしたら、aws,gcpと言ったクラウドサービスベンダーの利用や、Google DataStoreやAWSのDynamoDBのようなSaaSのデータストアの利用についての項目かスマホでのMMO開発の項目が追加されれば十分だろう。

ゲーム開発が変わる! Google Cloud Platform 実践インフラ構築 (NextPublishing)

こちらの本は、まさにGoogle Cloud Platformを利用したゲーム開発について書かれている(私は、7章のBigQueryを利用したデータ分析基盤の作り方について書いている)。この書籍では、DataStoreを使った1ワールドのサーバの作り方については書いていないが、その他のGCPを使った場合の参考にはなるだろう。


脚注





  1. 『Pok「é」mon GO』の表記がめんどくさいので。  



  2. 海外は、ジョブの説明がしっかりしていて、どういう技術を使ってそのサービスが作られているかを推測しやすい。 まあ嘘ついている可能性もあるが、それをする利点があまり無い(嘘の求人で、技術的にミスマッチな人が採用されても困るから)。 



  3. MMOとは、大規模な多人数で行うオンラインゲームのことで、例えば、FF14などが有名。 



  4. 最近の技術のため。使い始めている企業もちらほら出ている。 



  5. 日本中探したってそんなに多くはいないが。 



  6. 一般的なオープンソースのRDBMS(MySQL,PostgreSQL)の場合。Oracle ExaDATAの様に札束で殴ってどうにかという手はあるにはある。 



  7. この記事にあるように、datastoreで保存したデータ量に応じて性能劣化が起こらないと書いてある。6. Datastore performance doesn't depend on how many entities you have  



  8. この記事によると「個々のエンティティに対する更新処理のスピードは、1~10回/秒程度 」とそんなに早くないようだ。2009年の記事のため現在はどうなっているか分からない。