CodeZine(コードジン)

特集ページ一覧

【デブサミ2012】大ヒットソーシャルゲーム「ドラコレ」、
アプリ制作サイドから見た運用ノウハウ

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2012/03/23 14:00

目次

モバイルソーシャルアプリ特有の仕組み

 廣田氏は、ドラコレのサービス提供における大きな問題として、「超高トラフィック」と「モバイルソーシャルアプリ特有の仕組み」を挙げました。後者で苦労した点として強調したのが「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秒問題」:なぜソーシャルアプリプラットフォームでは「5秒」のタイムアウトが必要なのか
「5秒問題」:なぜソーシャルアプリプラットフォームでは「5秒」のタイムアウトが必要なのか

マイクロバースト問題

 もう一つ、頭を悩ませたのが「マイクロバースト問題」でした。これは前述の「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だけを増やさないようにするとなると、ソースの実体にも手を入れなくてはなりません。

 このように、いくつかのオープンソースコードの改造や、ミドルウェアのパフォーマンスチューニングを実施した結果、この半年間で公開停止になることはなくなったといいます。

「マイクロバースト問題」:SYNパケットのロストによるTCP接続の遅延が潜在的な問題だった
「マイクロバースト問題」:SYNパケットのロストによるTCP接続の遅延が潜在的な問題だった

  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:【デブサミ2012】セッションレポート

もっと読む

著者プロフィール

  • 吉澤 亨史(ヨシザワ コウジ)

    元自動車整備士。整備工場やガソリンスタンド所長などを経て、1996年にフリーランスライターとして独立。以後、雑誌やWebを中心に執筆活動を行う。パソコン、周辺機器、ソフトウェア、携帯電話、セキュリティ、エンタープライズ系など幅広い分野に対応。

あなたにオススメ

All contents copyright © 2005-2022 Shoeisha Co., Ltd. All rights reserved. ver.1.5