取材

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


スクウェア・エニックスの人気RPG「ドラゴンクエスト」シリーズの最新作「ドラゴンクエストX(ドラクエ10)」はシリーズ初のオンライン作品となりましたが、その舞台裏は一体どうなっていたのか。ゲームの世界観を支えるサーバシステムがどのように構成されているのかということや、ドラゴンクエストⅩならではの仕組みや機能から開発の苦労話まで、株式会社スクウェア・エニックス開発部プログラマ森山朋輝さんが語っています。

タイトル | CEDEC 2012 | Computer Entertaintment Developers Conference
http://cedec.cesa.or.jp/2012/program/NW/C12_P0040.html

森山朋輝:
皆様、本日はお集まり頂きどうもありがとうございます。このセッションを担当させて頂きます、株式会社スクウェア・エニックス開発部所属の森山朋輝と申します。どうぞよろしくお願いいたします。今日はドラゴンクエストXというタイトルとは言え、テーマはどちらかというとサーバサイド、マニアックなテーマなので、私のイメージトレーニング的には30人くらいを想定していたんですが、これだけ人が集まってしまってどうしよう、というところなんですけれども、精一杯がんばりますのでよろしくお願いします。


さて本日のセッションなんですが、このような流れで進めさせて頂きます。まず、本セッションの概要についてですね。ドラゴンクエストXの舞台裏とは言ってはいますけれども、具体的にどういった内容なのか、ということを簡単に説明させていただいた後で、実際にサーバ側の設計や開発がどのように進んだかというのをご紹介したいと思います。あと、せっかくもうサービスが開始していますので、現在稼働しているサーバがどういう状況になっているかというのも、怒られない程度にご紹介してですね、最後にまとめ、という形で進めさせて頂きたいと思います。


本題に入る前にですね、まず簡単に自己紹介だけさせて頂きます。私はスクウェア・エニックスで2006年から働いておりまして、当時はモバイル事業部というところに配属されて、サーバプログラマーとしてモバイル関連のウェブの開発であったり、課金システムやゲームサーバを幅広く経験した後で、今はドラゴンクエストXの開発チームに合流しております。私は元々大学を卒業して最初に就職した会社が日本オラクルというデータベースの会社だったこともあってですね、これまで大小様々なデータベースの設計とか、構築に携わってきたこともあって、現在スクウェア・エニックスでもデータベース周りの仕事を担当することが非常に多いです。その流れで直近では時々弊社の別タイトルであるFINAL FANTASY XIVのお手伝いなどもちょっとしながらですね、ドラゴンクエストXのバックエンド開発を担当しております。


さて、本日のセッションの概要の説明に移りたいと思います。先ほど私は「バックエンド」という単語を何気なく使ってしまったのですが、実のところ、これだけではまだちょっとどういうものなのかイメージがつかめない、という方もいらっしゃると思いますので、まずはドラゴンクエストXの全体的なサーバ構成を紹介した上で、今日のテーマとなるバックエンドというのが具体的にどのあたりなのかというのをご説明させて頂きたいと思います。


ドラゴンクエストXのサーバ群はですね、大きく分けると4つに分類することができます。この分け方自体は、世間にいろいろMMOがありますけれども、それほど大差はないので、「なんだ普通だな」と拍子抜けされる方もいらっしゃるかもしれません。順に説明していきますと、まず1番と書いてあるのがロビーサーバですね。こちらでは、他のMMOですと「認証サーバ」とか「ログインサーバ」とかいろいろな言われ方をすることがありますけれども、その名前の通り認証処理を行うサーバです。ドラゴンクエストXの場合は、いわゆる冒険の書というものを作成したり削除したり、そういったアカウントの管理をするところであります。次に2番のゲームサーバです。まさにモンスターを動かしたり、イベントを制御したり、本当にゲーム本体を担当するサーバです。実際にはゲームサーバの役割によって数種類あるんですけれども、本セッションの主題とは外れてしまうので、ここでは簡単にゲームサーバとひとくくりにさせて頂いています。続いて3番ですね、ロビーとかゲームサーバの後ろにあるバックエンドですね。データベースやキャッシュから構成されるサーバ群を本日は便宜上バックエンドと呼ばせて頂いています。ここについてはこの後で詳しく紹介させて頂きます。最後は4番、これはWebと書いてありますね。ドラゴンクエストXではですね、ゲーム内のデータと連動する「目覚めし冒険者の広場」というウェブサイトがありまして、自分で他のプレイヤーのゲームデータを参照したり、他のプレイヤーとコミュニケーションをとったりというサイトとなっています。こちらもバックエンドを経由して様々な機能を実装しております。


先ほどドラゴンクエストXのサーバ構成において、こういう分類自体は特殊なものではないと申し上げましたが、実はバックエンドの構成にはひとつの大きな特徴があります。これからご紹介しますが、それが今日の本題になってきます。弊社の他のタイトルを含めてですね、MMOに限らず、多くのオンラインゲームでよくとられるサーバの構成というのは、このように独立したサーバのセットを複数用意します。


ゲームによって言い方は違いますけど、多くの場合ワールドとかサーバとか言われていて、多くのサーバやワールドを分けて運用しています。作品がヒットしてお客さんがたくさん来てくれて、このサーバセットをどんどん増やしていくことでですね、比較的低リスクでシステムを拡張することができます。今日ここにいらっしゃっている多くの方にとっては目新しい話ではないかと思いますが、例えば昨今ですとAmazonのネットサービスのような、いわゆるパブリッククラウドと呼ばれるサービスとの相性も非常によいので、昨今ではオンラインゲームのサーバ構成としては王道と言っても差し支えはないかと思います。リスクの低さと拡張性の高さで言えば非常に優れた方式ではあります。それに対してドラゴンクエストXではですね、ひとつの絵で描きますと、こういう構造になっています。


ゲームサーバを人数に応じて増やすことができるんですが、データベースは実はひとつしかありません。データはすべて1箇所で一元管理されています。先ほどのページでご紹介したこちらの構成はですね、非常にメリットも多いんですが、ひとつデメリットがありまして。あるプレイヤーの、他のワールドにいるプレイヤーとのやりとりが非常に制限されてしまうんです。もちろん大抵の場合は、そのデータが違うデータベースにあったりするので、どうしてもそういう制限が生じてしまいます。ところがですね、ドラゴンクエストXでは「同じゲームをプレイしているのに一緒に遊べないという事態はだめだ」という発想が当初からありまして、このような構成で作ると最初から言われておりました。「みんなが一緒に遊べるように」と言うと聞こえはいいんですけれども、実際のところは、昨今のトレンドであるスケーラビリティとか負荷分散といった技術とは180度逆を行く方向なので、結構、実はムチャぶりなことだったんですけれども、まあこれはドラゴンクエストXのサービスをする上で必須だということだったんで、この難題をどのように実現していったかというのがこのセッションの主題となります。ちなみにちょっと余談になりますけど、このデータベースは1個でやってね、と言われた時、私はドラゴンクエストXの開発チームに入った直後で、「大変ですよ、本気ですか」とか言ってたんです。当時、実は私はそのドラクエのオンラインを作るということは知っていたんですけれども、ナンバリングタイトルだということは知らなくてですね、「どのくらい人が来るのかな、がんばればなんとかなるかなあ」と思っていたんですが、その直後に実はナンバリングタイトルだということを知ってですね、愕然としたという思い出があります。その時はもう引くに引けない状況だったので、どうにかするしかないな、という状況で設計や開発がスタートしました。

先ほどの「世界はひとつ」というコンセプトは、発想の段階からすると分かりやすいんですけれども、プログラマー視点から見ると、負荷がたくさんくるよということだけで、実は何も決まっていないに等しいんです。これだけでは設計も開発も何もできません。設計図も青写真も何も描けない、ということなので、いろいろとヒアリングをして決められることから決めていきました。

まず最初に決めたことなんですけれども、扱う大量のデータの最終的な取り扱いやすさを考慮してRDBMSに格納しようというところから決まりました。


ちょっとこのセッションではRDBMSというのは長いのでDBと略させて頂きます。データの取り扱いやすさというのは、単に保存したりロードできたりすればいいというものではなくてですね。例えば、「ここの値は世界全体で必ずユニークにしたい」とか、あるいはデータを集計したり、もろもろの調査をしたりする時は、なんだかんだ言ってSQLというのは非常に使いやすい、使い勝手がいいものです。あとはまあ、バックアップ運用のやりやすさとかも考えてDBという選択肢はありかなということで、データベースを使うということを選択しました。ここで使っているデータベースは当時の弊社の開発や運用のノウハウを考慮してOracleを採用しています。あとですね、データベースは結局1個しか持っていないのでクラスタ構成にして多少の拡張性を持たせようというのは決まっていったんですが、それだけではやっぱり不安だったので、どうにかしてキャッシュサーバをうまいこと使って負荷分散をしないと危険だ、というところまでは決まっていました。

今度はもうちょっと設計寄りの話なんですども、実はこのデータベースにアクセスするプログラムというのがいくつかあるというのは当初から決まっていました。


メインとなるのはC++で書かれたゲーム関連のプログラムなんですけれども、他にもWebですね、こちらはJavaで書かれていますし、他にもToolsとかスクリプトとか、実はいろいろなゲームがデータベースに接続します。この時にある処理を全ての言語で同じように実装していくというのは非常に冗長なので、Oracle側にSQL言語で書かれたAPIを実装して、どんな言語からでも、全くその実装のことが分からなくても、同じ処理が呼び出せるという手法を取っています。特に私がFINAL FANTASY XIVのお手伝いをしていた頃、FINAL FANTASY XIVのThe Lodestoneっていう連動ウェブサイトがありまして、こちらの生みの親がちょうど今、あの真ん中あたりに座っていますけれども、彼が非常にいろんなゲーム内のデータにアクセスすることにいろいろ四苦八苦していたので、ドラゴンクエストXでも同じようなことをやる時は、なるべくいろんなプログラムが簡単にゲーム内のデータにアクセスできるようにしたいんだ、ということで、こういう設計で進めていきました。

もう1個。実はアーキテクチャ的なところで決まったことがあります。これはデータベース中継サーバと言っていますが、文字通りメインとなるゲームサーバとデータベースの間を中継するためのサーバプロセスなんですけれども。なぜこれが必要になってしまうかというとですね、実はドラゴンクエストXのサーバプロセスというのは、もう数が数千、4ケタに達する数が動いてくるので、これをOracleに全部一度につないでしまうと、それだけでOracleのメモリがなくなってしまうというのが分かっていました。なので、データベース中継サーバと呼ばれるサーバは300~400くらいの数になるんですけれども、これがデータベースのセッションを取りまとめることでOracleのメモリが枯渇したりするのを避けようというのが決まりました。実際にはデータベース中継サーバは他にもこの後でいろいろな役割を担うことになるんですが、それは後ほどご説明します。なお、この絵はゲームサーバ視点で描かれています。DB中継サーバがたくさんあるんですけど、ゲームサーバは適当なDB中継サーバを選んでつなげばよくてですね、DB中継サーバというのがひとつ落ちてもゲームサーバはあきらめて別のところにつなぐので、これは1個や2個が落ちただけではプレイヤーのみなさんは気づかないようになっております。


あとですね、ここはどちらかというとゲームの機能面の話になってくるんですけれども、ヒアリングを進めていくとですね、データベースはセーブ・ロードだけではダメで、他にもいろいろやらなくてはいけないことがある程度分かってきました。


ここで紹介しているのはドラゴンクエストXで実装されている様々なプレイヤー間のやりとりを促進するための機能なんですけれども、こういったものを、例えばワールドの、本当にシステム全体でデータを共有したり、あるいはログアウトしている人ともデータのやりとりをする必要があるということで、やはりデータベース側でロジックを実装してしまうというのが現実的だったということもあって、ドラゴンクエストXのデータベースはセーブ・ロード以外にもいろいろな機能を包含しています。

さて、ここまで、いろいろヒアリングをして大まかなバックエンドといいますか、DBの満たすべき仕様というのが決まっていきました。ここからさらに具体的な実装に焦点を当てていきたいと思います。先ほどはデータのセーブとかロードとか、一言で片付けていましたが、実際にプレイヤーのセーブデータって「じゃあどうなっているのか」というのを。あまりこれは詳しく話すなと言われているんですが、簡単に紹介させて頂きます。ドラゴンクエストXのセーブデータの実態というのは、C++の構造体の集合からなる構造体です。こういった各構造体をデータベースのテーブルにマッピングしてセーブやロードを行えば、それでOKといえばOKではあるんですけれども、ドラゴンクエストXの場合はこのセーブデータの構造体のサイズが非常に大きくて、一人あたり多分数百キロバイトにはなると思います。さらにテーブル自体に、数十のテーブルに一人のプレイヤーデータを分割させて保存する必要があります。なので「マッピングしてデータベースに保存すればいいじゃない」と言えばその通りなんですけれども、この処理をそのまま素直に実装すると非常に重くなってしまいます。こういったデータのセーブとかロードというのはゲームの開始時とか終了時だけではなく、実はゲーム中でもかなりの頻度で行われます。例えばプレイヤーが街に入ったり洞窟に入ったりする度に、あるいはエリアの移動とかの時にも数百キロバイトのデータをセーブしたりロードしたりというのはあります。ここが重いとゲーム全体がすごい重くなってしまうので。そのため、どうやったらもうちょっと快適にゲーム全体が動くかな、というところで、先ほどのデータベース中継サーバを経由してもうちょっとデータベースに楽をしてもらおうということで、こういう構成をとっています。考え方としては非常にシンプルで、よくあると言えばよくあるんですけれども、セーブデータ、先ほどの数百キロバイトの構造体を、そのままシリアライズしてそのままキャッシュサーバに保存してしまえ、というシンプルなものです。ここで使っているキャッシュサーバは、もうご存知の方も多いかと思いますがKyoto Tycoon、データのシリアライズにはMessagePackを使用して、非常に高速なデータのセーブ、ロードを実現しています。この法則ですとKyoto Tycoonの数をどんどん増やしていけばシステム全体としてのセーブとかの負荷をですね、どんどんすっきりさせることができるので効果的です。


セーブ、ロード処理の大半をキャッシュに任せることでデータベースは楽になるんですが、それだけではだめで、最終的にはどこかのタイミングでOracleに保存する必要があります。ここに書いてある主なタイミングというのは、ログアウトする時、プレイヤー間で何かデータが移動する時、そして定期的に、と書いてありますが、特に重要なのが2番目ですね。


アイテムがある人から別の人に移った時に、そのうちの片方の人だけのデータが正しく保存されて、片方が巻き戻ってしまったりすると、アイテムが消滅したりあるいは複製したりという、あまりよろしくない事態になってしまうので、こういうタイミングでは必ずデータベースの保存をする必要があります。まあ、1番目のログアウト時と3番目の定期的にというのは、これは単に、キャッシュのみに保存されたまま、データベースには保存されていない、というデータがないようにです。こういったタイミングでデータベースの保存を行なっています。この時点で「なんだ、やっていることは実は結構単純なんだな」とお思いの方も多いと思いますが、その通りです。ですが、ドラゴンクエストXの場合、ひとつよかったという点はですね、これから簡単にご説明しますが、チューニングですね。このあとのチューニングフェーズがバックエンドについて言えば非常にうまくいった、というのがあります。

じゃあチューニングについてはどういうことをやっていたか、と言いますと、こちらですね。


バックエンドのチューニングの主体となっているのは、こちらの負荷テスト専用の検証クライアントです。開発室内では「ぼっと」「ぼっと君」とか呼ばれています。こちらが非常に高性能な負荷検証クライアントとなっていまして、ゲームにログインして新出キャラをキャラメイクするところから、いろいろなスクリプトで制御したり、移動したり、アイテムを使ったり、敵を探して戦闘したりと、かなりの精度でプレイヤーの動きをシミュレートすることができます。これもLinuxのプログラムなので、サーバを大量に並べて、数十万のクライアントをサーバに対して投入していくということで、どんどん負荷検証を進めていきました。実際、最初は数百体を投入するだけでサーバがいっぱいいっぱいになってしまったんですけれども、原因を見つけてもう1回テストをして、また直して、テストをして、というのをひたすら繰り返すことで、システムの使用人数が千、二千、五千、一万と伸びていきました。最終的に、現在ではバックエンドは数十万の接続が来ても問題なくさばけるというところまできています。

ちょっと時間がなくなってきたので少し押します。負荷検証クライアントの中で、負荷検証クライアントを投入してどういったところをチューニングしていったか、というところを簡単にご紹介します。これはサーバ開発を経験された方であれば割と一般的かと思いますけれども、1つ目はAPIのコール回数ですね。これは言い方を変えると、本当ならこんなにたくさん呼ばれていないはずのAPIがなんでこんなたくさん呼ばれているのか、というのを早めに発見できた、ということですね。


実際は仕様がいつの間にか変わっていたりとかいうことで、結構起きていたりしました。2つ目はですね、これもデータベースのチューニングではある意味王道と言いますか、必ずやることだとは思います。単体テストレベルでは結構見つけにくいものを、大量に大規模な負荷検証をやることで大惨事になる前に見つけることができました。最後はですね、これが実は、すごく重要だったんですけれども。キャッシュサーバにデータを保存する時に、接続数が増えていくと真っ先に限界が来るのはどこかと言うとですね、実はゲームサーバとデータベース中継サーバの間のネットワークの帯域が先になくなってしまう、尽きてしまうということが判明しました。これはさっきの数百キロバイトのデータをそのまま送っていたのが原因なので、圧縮しないとまずいということで、実際のセーブデータを使ってLZ4ですとかGoogle Snappyといった圧縮ライブラリをいろいろ検証した結果、ドラゴンクエストXのセーブデータと相性が良かったLZ4を採用しました。これで圧縮することで、実際数百キロバイトあったセーブデータが1%から5%くらいまで圧縮されて効率良くネットワークとかキャッシュを使えるようになっています。ちなみに、なんで最初からやらなかったのか、とツッコミを受けそうですが、当時はゲームサーバ側がまだ性能的にいっぱいいっぱいだったんです。余計な処理を入れる余裕がなかったというのもあって、ちょっと後回しになってしまいました。終わってみれば早めにやっておいた方がよかったというところではあります。そして、こういった負荷試験をやった上で、「どうにかいけるかな」ということで8月2日にサービスを開始しました。

最後に、おそらくここにいらっしゃるみなさんは「今、実際にどうなっているのか」というところに少し興味があるかと思いますので、簡単にご紹介します。


まずデータベースなんですけども、現在ドラゴンクエストXのデータベースはですね、秒間あたり数万単位のクエリーが飛んできていますが、割と問題なくさばけているというのが現状です。クエリーのレスポンスタイムは目標値だった10ミリ秒以下でほぼさばけているんですが、負荷試験のシミュレーション通り、負荷の傾向が出ていたので、やはり負荷試験に手間暇をかけてよかったな、というところです。ただ一部、やはり想定外のものも現状出ています。先ほど簡単にご紹介しました「旅人バザー」と呼ばれるアイテムの売買ですね。こちらの検索処理が、実装としては単純なセレクト処理とインデックスでチューニングしているだけなんですけれども、こちらのコール回線が予想の数十倍くらいコールされているので、ちょっとここは今後さらなる性能拡張が求められるということで、もう一工夫していった方がいいかなと思います。

あとですね、「順調ですよ」というだけではおもしろくないかな、と思いますので、これも怒られない程度に、こんなトラブルがありましたよ、というのをご紹介します。


1個ですね、これは私がやらかしてしまった例なんですけれども、デッドロックによるデータベースのNGを1回引き起こしてしまったことがあります。データベースの実装をする時にですね、キャラ単位のデータがデッドロックを起こさないというのをすごく慎重にチューニングしたんですけれども、バザーの処理というのは金の単位がアイテムの種類、アイテムごとにいろいろデータを持っているので、アイテムを出品するという処理と別の人がそのアイテムを買うという処理が、本当に千分の一秒未満だと思うんですけど、重なるとNGになる、というタイミングがありまして。これはちょっと負荷試験でも検出できなかったんですが、サービス開始後、8月7日ですかね、1回起きてしまいました。今では解消しているんですが、パフォーマンス的なトラブルがバックエンドについて言えばほとんど出ていなかったので、これは非常に個人的には悔しい一件でした。

最後に、自分がたずさわったこのドラゴンクエストXの開発について、重要だったと感じるポイントを簡単にお話ししたいと思います。1つ目はですね、当たり前だと思われるかもしれませんでれども、「負荷試験は本当に大事だな」ということでした。これまでサービスを開始してから、残念ながらドラゴンクエストX全体としてはトラブルが多少は出てしまっているのですが、やはり原因を見てみるといずれも負荷試験が難しい箇所であったとか、テストのシナリオから漏れてしまっていた箇所というのがほとんどです。なので、負荷試験はすごい、と。多分、私が今まで経験したプロジェクトの中で、負荷試験にかけた手間というのはダントツでこのプロジェクトが1番だったんですけれども、それに見合った成果は出たな、というのがひとつあります。そしてもう一つよかったなと思っているのは、開発にたずさわったいろんなメンバーの間で、目標とかビジョンの共有がはっきりできていた、というのがあります。これはどういうことかと言いますと、ドラゴンクエストXがオンラインになるということです。最初いろんなネガティブな反応があることは予想してはいたんですけれども、でもそういうことを踏まえた上で関係しているメンバーが、それでも大勢の人に遊んでいただけるゲームになるんだということを信じていたということです。例えばシーンを決める時であったとしても、サーバの構成を考える時であったとしても、それは本当に数十万の人に大丈夫なんですか、というのをベースにですね、物事を決めていったので、結果的に、比較的安定したバックエンド、サーバが構築できたのではないかと思っています。


さて、長くなりましたがそろそろ時間なので、私からのお話はそろそろおしまいとなります。プロジェクトに参加した時は、サーバのアーキテクチャが決まってバックエンドだけであとは空白だ、という状況で、両手両足を縛られた状態からのスタートだったんですけど、本当に自由にやらせて頂き、非常にやりがいがありました。今後ドラゴンクエストXをプレイされる機会がありましたら、一瞬でも本セッションのことを思い出していただければ幸いでございます。本日はご静聴ありがとうございました。

この記事のタイトルとURLをコピーする

・関連記事
「一つでも多くの作品を残して死にたいです」サイバーコネクトツーと松山社長のすべてがわかるインタビュー完全版 - GIGAZINE

オンラインゲームを「オカンでも説明無しで楽しめる」ように作るためにすべきこと - GIGAZINE

日米ゲーム開発における最大の違い「レベルデザイン」を本家が語る - GIGAZINE

「日本のゲームが持つ問題点」や「開発における日本とアメリカの明確な違い」を最前線にいる当事者がハッキリと語る - GIGAZINE

スクウェア・エニックス「ドラゴンクエストX(ドラクエ10)」発表会の様子まとめ - GIGAZINE

in 取材,   ソフトウェア,   ゲーム, Posted by darkhorse_log

You can read the machine translated English article here.