ピーク時のhttpリクエストは秒間5桁に上る
2012年2月16日、「Developers Summit 2012」において㈱コナミデジタルエンタテインメントのドラコレスタジオ戦略室マネージャーの廣田竜平氏が「大ヒットソーシャルアプリ『ドラゴンコレクション』の裏側~超高トラフィックを支えるアプリ・インフラの“明日から使えるテクニック” 限定紹介!」というセッションを講演しました。
廣田氏は大学卒業後、KONAMIのアミューズメント機器部門に入社し「ドラムマニア・ギターフリークス」「クイズマジックアカデミー」シリーズなどのプログラムを手がけた後、オンラインゲーム・モバイルゲームの部門に異動し、いくつかのタイトルのディレクションやプロデュースを担当した経歴の持ち主。ドラコレでは、技術面の責任者としてアプリ・インフラの両面からの方針決定、課題解決を担当しています。
ドラコレは、もはや説明する必要がないほどの普及を果たしたソーシャルゲーム。SNSサイト「GREE」で展開しており、登録会員数は550万人(2012年2月時点)を突破しています。従来、クエスト・バトルが中心であったソーシャルゲームに「ガチャ」や「合成」といったカード収集の要素を取り入れることで、ユーザーの絶妙なモチベーションフローを実現し、以降の国内ソーシャルゲーム市場に大きな影響を与えています。
「ソーシャルゲームは名前に『ゲーム』が含まれてはいますが、技術的に見ると『Webサービス』です」という廣田氏。人気が出るということは、それだけトラフィックが高くなるということ。ドラコレの場合、イベント開始直後などピーク時のhttpリクエストは、明言を避けましたが秒間5桁に上るといいます。このリクエスト数には画像などの静的データは含まれていないため、PHPで作られた動的ページへのアクセスがこれだけあるということです。単純にPVだけで比較すれば、国内の大手ポータルサイトにも匹敵する値かも知れません。KONAMIでは3桁におよぶ台数のサーバーで、このトラフィックに対応しています。
ドラコレを支えるシステムは「わりと教科書通り」
ドラコレのサービスに使用しているサーバーは、CentOS、Apache、MySQL、PHP+APCといった一般的なLAMP環境で、動的ページはすべてPHPで制作されています。KVSはmemcachedのみでNoSQLは使用していない、わりと教科書通りな「普通の」構成。ロードバランサー(LB)にはソフトウェアLBの「Zeus」を採用しており、LB1台ではすべてのトラフィックをさばき切れないのでDNSラウンドロビンを併用しています。
増え続けるユーザー数・トラフィックには、基本的にはスケールアウトで対応しており、たまにスケールアップも実施。フロントサーバーのスケールアウトは単純に増やすだけで対応できますが、RDBMSのスケールアウトは、Read性能がボトルネックなのであればReadレプリカを追加し、機能分割とシャーディング(水平分割)をひたすら続けるといいます。しかし、実際に超高トラフィックに直面してみると理屈通りに単純にはいきませんでした。
ドラコレのシステムは、当初パブリッククラウドを利用していましたが、現在は専用ネットワークを構築しています。この背景には、パブリッククラウドならではの複数の問題があったといいます。廣田氏は具体的な問題として、物理ディスクを占有できるサービスがなかったため「ディスクI/O性能が不安定」だったこと、「内部ネットワークのトラフィックの限界が分からない」こと、「クラウドサービス側のメンテナンスに都合を合わせる必要があった」ことを挙げました。
つまり、パフォーマンスの善し悪しではなく、パフォーマンスが不安定であることが問題だったのです。また、パブリックなサービスゆえに、どうしても自分たちでは制御できない要因があります。これらの問題は、一般的なWebサイトであれば問題にならないレベルのものでした。しかし、超高トラフィックと「モバイルソーシャルアプリ特有の仕組み」では、この問題は非常に大きなもので、最終的にドラコレ専用の環境にシステムを移行するに至ったといいます。
「引っ越し」の課題はメンテナンス時間
パブリッククラウドからドラコレ専用環境へのシステムの引っ越しにおいて、一番の課題となったのは「いかにメンテナンス時間を短くするか」。もちろん、引っ越しといっても物理的にサーバーを運ぶわけではなく、新しい環境にアプリとデータを移す作業です。Webサーバは引っ越し先の環境に同じプログラムを設置しておけばよいだけでしたが、問題となったのはデータベース。この段階で総データサイズは数百GBになっており、数時間のメンテナンスでコピー&展開できるサイズではなかったのです。
そこで、レプリケーションを利用して引っ越し先のデータベースをリアルタイムに同期させることにしました。万一、引っ越し後にトラブルが発生して旧環境に戻すことも考慮し、引っ越し後もしばらくは逆方向にレプリケーションを実行。旧環境と新環境は物理的に500km以上も離れた場所にあったため、理論上は問題なく引っ越しできると分かっていても、実施するまではドキドキだったといいます。結果、メンテナンスも短時間で完了し、無事に移行することができました。
モバイルソーシャルアプリ特有の仕組み
廣田氏は、ドラコレのサービス提供における大きな問題として、「超高トラフィック」と「モバイルソーシャルアプリ特有の仕組み」を挙げました。後者で苦労した点として強調したのが「5秒問題」と「マイクロバースト問題」です。国内モバイルソーシャルゲーム各社が提供しているモバイルソーシャルアプリのプラットフォームでは、エンドユーザーからのリクエストはモバイルソーシャルゲームのガジェットサーバー(ドラコレの場合はGREE)で認証を得た後にサービス提供者(ASP)のコンテンツサーバー(ドラコレの場合はKONAMI)に届きます。リクエストに対するレスポンスも、ガジェットサーバーを経由してエンドユーザーに届きます。
5秒問題
5秒問題とは、ガジェットサーバーのリクエストに対してコンテンツサーバーは5秒以内にレスポンスを返さなければならないというものです。レスポンスに5秒以上かかったり、エラーレスポンスを返すといったことが規定回数以上行われると、GREEから公開停止にされてしまい、SAPはDeveloper Centerから手動で再公開の設定を行う必要があります。
これは、GREEのガジェットサーバーに待機プロセスが増え続けてしまうことを回避する措置です。アプリケーションのバグや、本当にサービスを継続できない状況であれば公開停止もやむを得ませんが、高トラフィック状態の瞬間的なパフォーマンス低下でも公開停止にされてしまうため、何かしらの対策が必要になります。
そこでKONAMIでは、レスポンスに5秒以上かかりそうな場合にはPHPの処理を中断し、「再度ページを開いてください」といったメッセージを返すことで、最悪の事態を回避することを試みました。もちろん、これはあくまで瞬間的なトラブルを回避するための措置です。
さらにPHPのソースコードにも手を加えました。PHPではset_time_limit()関数を使ってスクリプトの実行時間を制限できます。しかしこの機能は、「PHPのプロセスが処理に費やした時間」だけが計測の対象になり、サーバーとの接続待ちや、ディスクI/O待ちの時間などは計測されません。このため、たとえ実行時間を4秒に設定しても、実際に制限がかかる頃には5秒経過している場合があるのです。これはタイムアウトの実装に setitimer()関数が使われていて、指定できる3種類のタイマーのうち「ITIMER_PROF」を使っているためです。
このタイマーに「ITIMER_REAL」を指定すれば、計測の対象を実時間に変更できますが、PHPは100%非同期シグナルセーフとはいえないため、変更にはリスクも伴います。そのリスクを承知した上でソースコードに変更を加えました。さらに「時間指定の単位を1秒未満の精度にする」「タイムアウト時のHTTP応答を変更可能にする」といった動作の変更、追加も実施したといいます。
マイクロバースト問題
もう一つ、頭を悩ませたのが「マイクロバースト問題」でした。これは前述の「5秒キャンセル」を実装する前のことですが、順調にユーザー数が伸びてトラフィックが増えていく中で、一部のレスポンスが極端に遅くなっていることに気づきました。しかも、遅延が発生するファイルに法則性がなかったのです。その後、遅延が発生しているレスポンスはすべて9秒前後で処理が完了していることに気づき、さらに調査した結果WebサーバーからDBサーバーへのTCP接続で時間がかかっていることが判明しました。パケット解析をした結果、時々SYNパケットをロストしていたのです。
TCP パケットの再送に関してRFCでは以下のように定義されています。
- RTT(Round Trip Time)が確定する前のRTO(Retransmission Time Out)は3秒
- RTOは再送するごとに倍に増やす
SYN送信時にはRTTが確定していないため、RTOは3秒になります。つまり、SYNパケットを2回ロストすると、TCP接続に約9秒かかります。1回だけロストするケースもありましたが、トータルで5秒以内にレスポンスできていたため気づかなかったのです。さらなる調査の結果、このパケットロスはスイッチのキューでの瞬間的なパケットあふれ(マイクロバースト)が原因であることが判明しました。定常的なトラフィックでは十分に余裕があったため、発見までに時間がかかってしまったのです。
この問題は、アプリのすべての通信箇所(DB、memcached、DNSなど)の接続タイムアウト・リトライを調整すれば最適化できるかもしれません。しかし、アプリ側に実装を委ねると、どうしても抜け漏れが発生しますしSYN_SENT状態のソケットが大量に滞留してしまいます。そこで、内側のネットワークに対するRTOを変更することで、この問題を回避したといいます。
具体的には、
- 変更前:初期 RTO = 3 sec / 再送のたびに RTO = RTO × 2
- 変更後:初期 RTO = 1 sec / 再送のたびに RTO 変更せず
としました。初期RTOの変更だけであれば、カーネルソースの定数定義を変更してビルドし直すだけで済みますが、再送のたびにSYNパケットのRTOだけを増やさないようにするとなると、ソースの実体にも手を入れなくてはなりません。
このように、いくつかのオープンソースコードの改造や、ミドルウェアのパフォーマンスチューニングを実施した結果、この半年間で公開停止になることはなくなったといいます。
「輪番アクセス」で予測不能な高負荷に備える
セッションの最後に廣田氏は、「輪番アクセス」の提案を行いました。システムの規模が大きくなると、新しい機能を追加する際の負荷テストが難しくなります。理想をいえば、本番環境と同じシステムがもう一つあれば、同じ条件での負荷テストを実施できます。しかし、コスト的にも運用管理的にも現実的ではありません。
現実的には、スケールダウンした環境で負荷テストを行い、その結果に係数をかけるのが一般的だと思われますが、規模が大きくなると単純計算では成り立たなくなると廣田氏は指摘します。このため、新しい機能の追加やイベントを実施するときの負荷予測は難しいものがあるのです。
最近では、過去の実績や各種パラメータ(CPU Usage、Disk I/O、DBサイズ、バイナリログなど)から総合的に判断して既存のシステムで対応できるか、システム増強を行うかを判断しているという廣田氏。こうした経験を重ねていった結果、リリース直後にパンクするようなケースは大分減ったといいます。しかし、それでも予測できなかったケースはあります。
そういった不測の事態が発生したときのために、輪番アクセスの仕組みを仕込んでいるといいます。輪番アクセスとは、エンドユーザーをIDからいくつかのグループに分け、定期的に利用できる範囲を変えていくという方法。この仕組みによって、サービスの開放率をコントロールできるようになります。
ゲーム全体へのアクセスだけでなく、特定の機能などに輪番アクセスの仕組みを導入するケースもあります。システム上の何かがパンクした場合、ボトルネックとなっているパラメータのグラフを見ながら、この開放率をコントロールしてピークをしのぐことができるのです。
まとめ
以上、Developers Summit 2012で講演されたソーシャルゲーム制作・運営における技術ノウハウの一部をご紹介しました。大規模ソーシャルゲームの裏側が、実に着実な技術の積み重ねて構築されていることがご理解いただけましたでしょうか。ソーシャルゲーム業界は、現在もっともエンジニア魂を刺激する技術的なチャレンジの尽きない領域の一つだと言えるでしょう。