はじめまして、株式会社エクストーンの仲山です。
今回、ニフティクラウドユーザブログに参加する機会をいただきましたので、ソーシャルアプリを公開、運用するまでを連載記事として書いていきたいと思います。
全体の流れ
この連載記事では、これまでに弊社がソーシャルアプリをリリースしてきた経験を踏まえ、クラウド環境とのつきあい方や、失敗から得た経験、TIPSなどをご紹介します。なお、具体的なソーシャルアプリの企画や実装の方法については触れませんが、 詳しい書籍がたくさんありますので、そちらをご覧ください。
今のところ以下の4回に分けての掲載を予定しています。
- 第1回: 企画・設計段階 (今回)
- 第2回: アプリの開発と負荷試験
- 第3回: リリースに向けた本番環境の準備
- 第4回: リリース後の運用
第1回は企画・設計段階と位置付け、ソーシャルアプリの特徴を簡単にご紹介し、一般的なサーバ構成とそのコスト試算を行います。
ソーシャルアプリの特徴
まず最初に、ソーシャルアプリの特徴をかんたんにご紹介します。
■ 利用者数の傾向
ソーシャルアプリの最大の特徴は、その利用者の増加傾向にあります。
通常のアプリであれば、広告や雑誌記事などによって利用者への露出を行ったタイミングで利用者が集中的に増加します。そのため、どれだけ大規模な広告を打つかなどによって、利用者数の増加をコントロールすることができます。
対してソーシャルアプリでは、似たような内容に見えるアプリが数多く存在することもあり、後出しの広告にそれほど大きな効果がありません。その代わり、リリース直後に掲載される「新着アプリ」ページに大きな広告効果があり、その時点で人気が出れば、利用者がその友達をアプリに招待することにより、一気に利用者が増加します。また、アプリの内容に満足することができなければ、一度離れてしまった利用者を呼び戻すことが難しくなります。
■ ソーシャルアプリの提供形態
ソーシャルアプリの提供形態には大きく分けて2種類があり、サーバへのアクセス方法がそれぞれ異なります。
・JavaScriptアプリ
携帯向けアプリでは利用することができず、PC向けおよびスマートフォン向けアプリでこの形態が取られます。
SNSのサイト上にIFRAME(インラインフレーム)経由でアプリ開発者が登録したHTML(Gadget XML)が表示され、そこから呼び出されたJavaScript上でアプリを実装します。また、利用者に対するユーザインターフェースは開発がしやすいFlashを利用し、その裏側でJavaScriptを呼び出している場合が多いようです。
JavaScriptは利用者のブラウザ上で実行されますが、アプリ上での利用者の動作に応じて、データの取得や、保存が必要になった時点で、 SNS側サーバを経由して、アプリのWebサーバに対して都度リクエストを行います。利用者の操作はJavaScriptが一旦受け取るため、連続して行われた複数の操作をまとめてサーバに送信する、などのアクセス軽減策が可能となります。
また、プロフィール情報などSNS側の情報を引き出すAPIは、原則としてJavaScriptのAPIとしてブラウザ上からSNS側サーバに対して呼び出します。
・HTMLアプリ
通常のWebサイトと同様に、ページ遷移ごとにサーバ上でページを生成します。
利用者の認証についてはSNS側で行うため、 SNSサイトのサーバが携帯端末の代わりにアプリのサーバにアクセスし、表示内容のHTMLを取得します。このHTMLにSNSサイトのヘッダやフッタ、広告などを付与して携帯端末に返します。
また、プロフィール情報などSNS側の情報を引き出すAPIは、 RESTful APIとしてアプリのサーバからSNS側サーバに対して呼び出します。
既にGadget XMLやJavaScriptにより画面が表示されているJavaScriptアプリと異なり、アプリのサーバがHTMLを返さなければ何も表示できなくなってしまうため、タイムアウトに対して厳しいペナルティが適用されます。タイムアウトが頻発した場合に、アプリに対して掲載停止や、新規利用者の受付停止などのペナルティが科されます。機会損失を避けるためには、表示時間をアプリ側でコントロールし、 SNS側のタイムアウト時間を超える前に、アプリ側で自前のタイムアウトページを表示するなどの対応が必要となります。
なお、PC向けアプリの例外として、ブラウザ三国志などIFRAME等を利用して通常のHTMLアプリとして実装されたソーシャルアプリも存在します。これらはブラウザ側からIFRAME直接アプリ側のサーバで提供するHTMLを表示するため、上記のタイムアウト制限は適用されません。
■ アプリの動作
特に携帯向けアプリで顕著なソーシャルアプリの特徴として、通常のウェブサイトに比べて大幅にPVが多い点があげられます。
ゲーム内での「成長」や「攻撃」などの利用者の行動ごとに連続して画面遷移を行うため、回線状況次第で一人の利用者から毎秒1PV以上のアクセスが発生する場合があります。また、JavaScriptやFlashで提供されるアプリにおいても、アプリの作り方次第で、マウスクリックの連打がそのままサーバへのアクセスとなります。
さらに、利用者毎の「持ち回数」を消費することで行動を行うパターンが一般的で、利用者が行動を行う度に、(1)その持ち回数を確認し、(2)持ち回数があれば減らし、 (3)残り持ち回数を表示する、というデータの取得・更新が発生します。そのため、データの不整合が起きないよう、 DBのレプリケーションや、メモリキャッシュを利用するのであれば特に注意が必要です。
また、アプリ利用者からの問い合わせを受けたときに追跡調査ができるよう、ユーザの行動をある程度記録する必要もあります。
このように、特にDBに対して厳しいという点がソーシャルアプリの特徴です。
企画・設計段階
このようなソーシャルアプリの特徴を踏まえて、実際にアプリの企画・設計を行っていきます。
この段階でサーバに関する事項として、以下のようなことを検討しておく必要があります。
・企画としてのゴール
・サーバ構成と性能目標の検討
・サーバ費用の試算
・ヒットしすぎた場合の対策
・ヒットしなかった場合の対策
企画としてのゴール
企画段階で、まずは目標とする想定アクセス量をざっくりと算出します。この想定アクセス量を元に、用意すべきサーバ数を算出します。
アプリに対する平均1日PVと、どれぐらいピーク時にアクセスが偏るかを示すピーク係数の2つがパラメータとなります。今回は、ソーシャルアプリがヒットしたとされる1日300万PV(月間9000万PV)というのを目標とし、時間を絞ったキャンペーンなどによる短時間へのアクセス集中は想定しないものとします。
項目 | 想定量 | 備考 |
---|---|---|
平均1日PV | 300万PV | 事業計画で目標とする1日PV |
ピーク係数 | 2.0 | ピーク時にアクセス頻度がどれだけ伸びるかの仮定 アプリの内容や想定利用者層に応じて変更します。 今回は時間帯によるアクセス増減のみ考慮して2.0としました。 |
平均秒間PV | 毎秒34.7PV | 平均1日PV ÷ (24時間×60分×60秒) |
ピーク秒間PV | 毎秒69.4PV | 平均秒間PV × ピーク係数 |
したがって、ピーク秒間PVである「毎秒69.4PV」というアクセス量が、安定して提供すべき目標値となります。
サーバ構成と性能目標の検討
次に、アプリの企画内容から、それを実現するためのサーバ構成を検討します。
今回の連載で扱うアプリのサーバ構成を以下のように決めました。
なお、mixi等のSNS側サーバについてはこの図では触れていません。
また、この時点でそれぞれのサーバの性能に対するアプリの性能目標を仮置きします。
アプリを実装する前の推測は難しいが大丈夫か、と心配する方も居ると思いますが、この時点ではあくまで試算段階ですので、他の案件での事例を参考に仮置きした目標値で大丈夫、問題ありません。また、この性能目標の「精度」が開発会社としてのノウハウの一つと言えます。
サーバ | 用途 | 性能目標 |
---|---|---|
Load Balancer | アプリへのアクセスを一番手前で受け取り、各Webサーバにアクセスを振り分けるリバースプロキシサーバです。 今後、モバイルアプリに対する際には、タイムアウト処理も行います。 Apacheやnginx、Poundなどが広く使われていますが、今回はnginxを利用します。 | 今回の規模ではCPU1コア/メモリ1GB |
Web (Static) | 画像ファイルやスタイルシートなど、静的なファイルを配信するためのWebサーバです。 nginxやlighttpd、Apacheなどが広く使われていますが、今回はApacheを利用します。 また、静的ファイルの送信処理は極めて負荷が低いため、実際のサーバとしてはLoad Balancerと同じ1台のサーバ上に集約します。 | |
Web (App) | 利用者の行動に応じて処理を行い表示内容を生成する、実際のアプリ本体のプログラムが動作するWebサーバです。 実際の開発言語にあわせて選択されます。今回はApacheを利用します。 | CPU1コア/メモリ2GBで毎秒10PV ページ本体のみ処理するため、PV=リクエスト数 |
Web (管理) | アプリ開発者が操作するためのWebサーバです。 アプリのデータの更新や、ユーザ問い合わせ対応のための調査を行うための管理画面等や、 利用状況把握のための集計バッチ処理等を設置します。 また、各サーバの監視や、DBのバックアップなどもこのサーバ上で行います。 | 今回の規模ではCPU1コア/メモリ1GB |
DB Master | アプリの情報を格納するマスタDBサーバです。 後述するレプリケーション遅延によるデータ不整合のリスクがあるため、 当面はアプリ本体からはこのマスタDBサーバのみを利用します。 |
今回の規模ではCPU4コア/メモリ16GB |
DB Slave | DBの内容をレプリケーションで複製したスレーブDBサーバです。 集計やバックアップなど、アプリの動作に影響を与えるような処理に、 このスレーブDBサーバを利用します。 |
今回の規模ではCPU1コア/メモリ1GB |
Cache | マスタDBサーバへのリクエスト数を減らすために設置するキャッシュサーバです。 プロセス再起動で記録内容が消えるオンメモリのキャッシュと、ディスクに記録内容を保存するキャッシュがありますが、 今回は前者のmemcachedを利用します。 | 今回の規模ではCPU1コア/メモリ1GB |
アプリへのアクセスが大幅に増えた場合は、マスタDBの分割やKVSの導入なども考慮する必要がありますが、まずはリリース時点での想定ということで、ごくごく基本的な構成としています。
サーバ費用の試算
それでは、ここまでの情報を元に、実際のコスト試算を実施します。
サーバ | インスタンス種別 | 台数 | 単価 | 合計 |
---|---|---|---|---|
Load Balancer / Web (Static) | Small | 1 | 13,335円 | 13,335円 |
Web (App) | Small2 | 7 | 18,144円 | 127,008円 |
Web (管理) | Small | 1 | 13,335円 | 13,335円 |
DB Master | Large16 | 1 | 91,927円 | 91,927円 |
DB Slave | Small | 1 | 13,335円 | 13,335円 |
Cache | Small | 1 | 13,335円 | 13,335円 |
総計 | 272,275円 |
ここで、Web (App)についてはインスタンスの種別によっていくつかの選択肢がありますが、以下のように最も安いプランとしています。
利用インスタンス | 1台あたり性能 | 必要台数 | 単価 | 合計 |
---|---|---|---|---|
Small2 | 毎秒10PV | 7台 | 18,144円 | 127,008円 |
Medium4 | 毎秒20PV | 4台 | 35,070円 | 140,280円 |
Large8 | 毎秒40PV | 2台 | 66,528円 | 133,056円 |
ただし、台数が増えることで運用コストも増加しますし、サーバスペックに応じて単純なかけ算で性能を予想しています。したがって、あくまでこの時点でのサーバ構成は試算のためのものに過ぎず、最終的にベストとなる構成はリリース前に実際のアプリを用いて計測して探ることになります。
アプリがヒットしすぎた場合の対策
アプリが想定を超えてヒットした場合に、サーバ環境としてどのように対策を取るかをあらかじめ検討しておき、「どうにもできない」という状況が発生しないようにすることが重要です。
■ Load Balancer / Web (Static)
このサーバがボトルネックとなる場合には、静的ファイルを別ドメインとし、サーバを完全に分離することで対策が可能です。また、それでも1台で足りなくなってしまう場合には、 ロードバランサー機能や、 DNS ラウンドロビンにて分散が可能です。
■ Web (App) と Web (管理)
Webサーバについては、基本的にアクセス増加に合わせてサーバ台数を増やすことで対策を行います。
あらかじめ設定済みのWebサーバからカスタマイズイメージを保存しておくことで、イメージ作成後に更新されたファイルのみを追加するだけで、すぐにサーバ追加が可能になります。また、各種ミドルウェアの構成の統一については、ChefやPuppetと言った構成管理ツールの利用が有効です。これについては、連載後半にて触れます。
■ DB Master
今回の構成では、既にニフティクラウドで可能な限り上位のサーバを利用しているため、これ以上のスケールアップができません。そこで、アプリの実装に踏み込んでいくつかの対策を行う必要があります。
・DBクエリ内容の調査
一定時間以上を要したクエリを記録するスロークエリログ機能はどのRDBMSにもありますが、これを有効にしてしまうと、DBサーバ全体の負荷が上がってしまい、本末転倒となってしまいます。
そこで、Maatkitに含まれるmk-query-digestの登場です。 tcpdumpによるネットワークレベルでのパケットキャプチャ結果を読むことができます。クラウド環境であればサーバの追加はすぐにできますので、サーバの追加で負荷を下げたWebサーバ側でパケットキャプチャを行い、クエリ全体の分析内容をアプリ開発者にフィードバックすることができます。
・スレーブサーバの追加
リリース時の構成では、DB Slaveはあくまで集計やバックアップ等のみに利用し、アプリ本体では利用しないこととしています。 DB Slaveサーバをそのままアプリ本体からも利用すると、集計やバックアップによりロックが発生し、処理が滞る危険があるため、新規にスレーブサーバを追加し、アプリ本体からの読み込みをそちらに回す事が可能です。
レプリケーションを利用する上で、遅延が発生するという点に注意を払う必要があります。特に携帯向けのソーシャルアプリでは、一人の利用者が1秒以内に繰り返しページを更新するような場合が多く存在します。レプリケーション遅延を考慮しないと、スレーブサーバ上の古い値を元に更新を行ってしまうと、負荷が多く遅延がある時間帯に、正しくデータが反映されないといった不具合が発生します。楽観的ロック(Versionパターン)等によりレプリケーション遅延による不整合を検知し、適切に対応を行う必要があります。
・DBの分割、KVSの検討
もし、ここまでの対策で追いつかないようであれば、テーブル毎のサーバ分割や、ユーザIDやタイムスタンプによるパーティショニングといった、Shardingを検討する必要があります。また、テーブルの利用傾向を分析し、それぞれに見合った特性を持つKVS等を併用することで、大幅な性能改善が実現できる場合もあります。
具体的な手法については、この連載の目的から離れますので省略します。
・DB Slave
基本的にはスペックアップで対応しますが、DB Masterの構成を変更した場合はそれに追従する必要があります。
・Cache
基本的にはスペックアップで対応します。
アプリがヒットしなかった場合の対策
ソーシャルアプリの場合には、一度公開したアプリの収益が思ったように上がらないからといってすぐに提供を中止することはできず、例えばmixiの場合には提供終了前にmixi事務局に連絡する必要があり、そこから45日間はサービスを続ける必要があります。あるいは、アプリの提供を続けながら企画内容を練り直す場合にも、収益が上がらない期間のコストを削減する必要があります。
上記の計算は全て25%程度の割引効果のある月額プランでの計算となっていますが、料金プランを従量に変更し、インスタンス種別を低スペックのものに落とすことで、その期間のコストを削減することができます。また、アプリのリリース時点では、最低台数分のみを月額プランとし、それを超える台数は従量プランとする使い分けも可能です。
特にソーシャルアプリでは、サーバ過負荷などで離れた利用者が再び戻ってくる割合が少ないため、リリース直後の新着アプリ欄からの新規流入に耐えることができないと、大幅な機会損失となってしまいます。そこで、リリース時点では従量プランで一時的に想定される限界まで台数を増やしておき、実際の負荷を見ながらサーバ台数の最適化を継続して行うことが重要です。
今回のまとめ
ソーシャルアプリの企画・設計段階にサーバインフラ側で検討するべき事項として、どのようにサーバ費用の試算をするか、また、アプリがヒットしすぎた場合、ヒットしなかった場合にどういうリスク管理をするのか、についてご紹介いたしました。
次回予告: 第2回 アプリの開発と負荷試験 「開発環境の充実はとっても嬉しいなって」
次回は、アプリの開発段階と負荷試験まで進める予定です。
夢の中で思いついたようなアプリを実際に用意しておきます。