DeNA Technology Seminar #1に参加しました。

DeNA Technology Seminar #1 Inside OpenSocial Container

3月16日に、株式会社ディー・エヌ・エーさんで開催された「DeNA Technology Seminar #1」 に参加してきました。

先日PHP勉強会に参加した時に、mixiのwebooさんが、今回のセミナー開催を告知されてて、とても楽しみにしていました。

セミナーを聞いた感想として、普段利用している2大ソーシャルアプリの裏側で、Perlがこんな風に活躍しているのだなと、感じる事のできたセミナーでした。

発表者の方々、関係者の方々、ありがとうございました。とても楽しく勉強になりました。次回も開催されれば是非参加したいです。

理解できていない内容も多く、帰ってUstreamを聞きながら、もう1週間経ちますが、メモを整理しました。
内容として誤解している部分がありましたら、ご指摘いただければ修正します。

◎発表 その1
Inside MBGA Open Platform API architecture
発表者:zigorouさん


MBGA Open Platformの実装を担当しておられるzigorouさんが、Open Platform API全般についての説明をしてくださいました。

概要

*WAFについて
WAFはCatalystを採用(但し、dispatcherとしての役割に限定して使用)。
Catalystについては、moose版を使用。特にCatalystらしい機能は使っておらず、Pluginも、ConfigLoader、Log::Dispatch、Unicodeだけを使用。


以前、CatalystについてのプロファイリングをDevel::NYTProfを使って実施した際、高コストの処理として、Class::MOPがたくさんピックアップされた。
結論的に、Catalyst Moose版を使えるのは、小中規模のサービスまで。
大規模開発の場合は、富豪的にコードを書くと後が大変。
現時点で運用中のCatalyst Moose版で困っているわけではないが、いずれ、Plack + 薄いWAFに差し替える予定。


*Webサーバーについて
Webサーバーはlighttpdfastcgiで構築。
fastcgi絡みであった過去のトラブル
・loadが高い時に勝手にbackendへの接続を絞ってしまった。
fastcgiからのresponse eventを受け取ったのに、responseを読めない謎のバグがあった。
lighttpdは、stableとは言いきれない!。

fastcgiはdeamon toolsで運用していて、deamon toolsのmultilogは使っていない。


MYSQLについて
DBへのアクセスについては、DBIx::DBHResolver、DBI等を使用。またSQL文については、SQL::Abstractを使ったり、生のSQL文を書いたりする。
MYSQLのストレージエンジンは、基本InnoDBで、擬似sequence用のテーブルや検索系テーブルのみMyISAMを使用。
DBはMaster×1、Slave×3、Backup×1で一つのクラスタとして構成。user情報など参照頻度の高いクラスターについては、slaveが数10台のような構成もある。
歴史的な経緯もあってラックが複数拠点にあったりして、replicationが拠点をまたぐ事もあるが、最近は専用線を増強したので、それほど気になる事ではない。


memcached更新用trigger専用slaveというのがある。
特定slaveのみtriggerを仕込み、更新のあったデータのみを別テーブルに抽出。
抽出したデータを読み込みmemcachedに突っ込んだりする。
キャッシュのデータを読み込んだ際にレプリケーションの遅延などはほとんど発生しない。


*開発について
svnでレポジトリ管理してるが、いずれgitに移行予定。

開発手順は以下のとおり。
(1)ローカルでテスト(Test::mysqld、Test::TCP
(2)stageにdeployして動作確認。
(3)sandboxにdeployする。
(4)serviceにdeployする。


*Deployについて
Archerを採用。
Archerの運用に関しては、基本そのまま運用しているが、サーバーの構成がたびたび変わるので、以前Yamlにホスト名を書いていた部分をプラグイン化したりしてる。

Deployの仕方は、rsyncして、lighttpdを落として、svc -t /service/myappしてlighttpdをあげる。
そのうちPlack with PSSPSS化したい。


CPANの管理について
CPANモジュールについては、rpmyum repostoryで管理してる。CPAN::Packagerを利用。
yum reposの更新および管理については、自社のお手製ツールを利用。
開発環境も本番と同じ、yum reposでyum groupupdateをしていて、開発環境もサーバー数が多いので、これらもArcherを活用。


*監視系について
・監視ツールはnagiosや、mysql系の監視には自社作成のツールで能動的にチェック。
・syslog-ngでログを集めてログの監視を行っている。当初はTCPでログ転送する予定だったが、現状UDPによるログ転送を実施。

アーキテクチャについて

*提供API
a) OpenSocial RESTful APIs => People、Appdata、Activity、Messageを提供。
b) mbga Game API(独自API)=> Payment、TextData、Ads、BlackList、NGWordなどを提供


※上記APIのうち、以下はいくつかを詳しく説明してくださいました。
*People APIについて(OpenSocial RESTful APIs > Perple)
・自分自身の情報を取得する場合(GET /people/@me/@self)
・viewer(閲覧者)自身のプロフィールを取得するパラメータ
・key-valueで簡単に取得できるので、memcachedでのやりとりが可能。


閲覧者の友達情報を取得する場合(GET /people/@me/@friends)
・アプリをインストールしている、していないを検索条件に指定。
( hasAppパラメータを「true」か「false」で定義 )
・最大1000件取得できますが、無茶はしないでくださいね。


友達情報取得する場合、複数のテーブルを参照している。


友達情報取得する際に発生した問題
max_allowed_packet問題
モバゲーの友達数は無制限なので、max_allowed_packetの値のdafault値1MBを越えてしまう場合がある。
対応として、
・クエリが単純に分割可能ならば分割してアプリでマージ。
・分割できない場合は、CREATE TEMPORARY TABLEコマンドで、一時テーブルを作成する。


*Message APIについて(OpenSocial RESTful APIs > Message)
Message APIとは、アプリがユーザーに、もしくはユーザーがユーザーに対して通知を行うAPIで、タイトル自身はアプリケーションごとに決める。
タイトル例) hidekさんから応援バトル依頼


Message/Activityを叩きまくるアプリに対する対策。
・特定条件を満たした場合の通知は一分間に一回に制限(cacheに格納)。
・アプリからのメッセージ送信については4時間に一通に制限(DBに格納)。


ユーザーにMessageが配信されるまで
Message API or 内部APIQ4Mにinsert(Open Platform以外でも怪盗ロワイヤルなどでこの方法を実施)
・Activity/Messageで2000万/day以上の通知があるため、masterの書き込みは制限したい。


MYSQL Partitioning
Massage/Activityで採用し、日単位で分割している。
Rangeが効くQueryだと高速。
保持期間をすぎたら DROP PARTITIONを実行する。
難点は分割に使ったカラムをuniqueインデックスに含めなければならないところ。


*Profiling
実行時間が敷居値を超えたものはログに書き出しを実施。
API、アプリごとにデータを収集し、最適化を実施。
DBIx::ProfileManagerで0.1%でSQLのProfile結果をログに書き出しを行う。


参考ページ
http://engineer.dena.jp/2010/03/dbixprofilemanager-sql-profiling.html

まとめ

好きな技術をチョイスしている。
CPANモジュールもありがたく利用させていただいている。

その上で、気に入らなければ、自らコードを書いたり、
テストをきちんと書いた上で変更する。

トラフィックが多いと想定外な事が多く、普段から
ケチ臭くプログラムを書く事が重要!。


◎発表 その2
mixiアプリプラットフォームについて
発表者:webooさん


次は、mixiのwebooさんが
mixiアプリプラットフォームについての説明をしてくださいました。


mixiアプリモバイルについて
現在、mixi Platformというオープン化戦略を展開。
mixi.jpの中でアプリを作れるもの => mixiアプリ
外部からmixiソーシャルグラフにアクセスして、アプリを作る=> mixi Connect


pcとモバイルでアプリを提供できるのは、mixiだけ。


pc版とモバイル版でいずれも、mixiアプリを実装する為にガジェットxmlが必要だが、ガジェットXMLの中で並べて併記することも可能。
pcから実行すれば、PC用のContent-Typeが読み込まれ、モバイルから起動すれば、モバイル用のContent-typeが読み込まれる。


mixiアプリモバイルの構成
mixiがアプリモバイルのプラットフォーム内部について
Aprication Proxy(HTMLファイル)と、
Media Proxy(画像/flashファイル)が存在する。


*Aprication Proxyについて
・HTMLファイルを処理する。
・User Flow APIタグの展開。
・広告タグの展開。
mixiヘッダー/フッターを追加する。
・UID/Cookieヘッダーを削除する。


*Media Proxyについて
・画像やFlashを処理する。
・response bodyのパースはしない。
・UID/Cookieヘッダーを削除する。
・ファイルサイズのチェック


●サーバー構成
サーバー構成は、mod_proxy + mod_perl + squid
アプリケーション情報はmemcachedに格納。
DBアクセスはほとんど無い。
フレームワークは使用しないで、スクラッチから実装している。


●負荷についてのお話
モバイル版のリリースが、仕様公開から正式オープンまで、6ヶ月。
PC版リリース時、多数のアプリが負荷によってダウンしたので、モバイル版では、同様の事がおこらないようにしたかった。


*正式リリース前に行った負荷対策と結果
(1)5秒以内にレスポンスを返さなければタイムアウトにする。
・一定回数タイムアウトされると、新規ユーザーの登録が不可に。
・更にアプリ一覧からも表示されなくなる。
・解除するには、mixiに対して報告をする必要がありとした。
(2)リリース前に負荷テストの実施状況をヒアリングした。
・負荷内容、負荷試験実施環境、負荷試験においての想定許容内容、実施日、結果を各SAPさんに問い合わせ。
・結果すべてのSAPさんから「問題なし」の回答 
・実際にリリースすると、ほぼすべてのSAPサーバーがjoin停止状態になってしまった。
・負荷に耐えた一部アプリだけが残った(一部のアプリは5日で100万人ユーザー達成!)


*リリース後の緊急対策
タイムアウト制限を10秒に緩和。
・画像ファイルのキャッシュを開始(squid上にて)。
・パフォーマンス向上のお願いを各SAPサーバーさんに行った。
・画像やFrashについての署名(OAuth Signiture)については、オプション化した。
・Devel::NYTProfを使ってプロファイリングも実施。


Opoen Social for Mobileは、SAPさんとmixi Platform双方が連携しないとうまく動作しない。


2009年10月〜11月にかけて
SAPに対して開発/運用に関するコンサルティングをした結果、
以下の事がわかった。
a). 開発言語は、PHPJavaが多い
b). DBはMySQLが多い
c). memcachedを使っていない。
d). 非同期処理を、mixiアプリ自体にforkで記述していた。
e). 環境がWebサーバー1台+DBサーバー1台というSAPさんもおられた。
上記の調査結果を踏まえ、環境向上に取り組んだ結果、負荷もだいぶん軽減された。


Plack + AnyEventモデルへの移行
mixi Platform自体でも、構成の見直しを行い、
3月上旬に、Plack + AnyEventモデルへの移行を実施した。


従来のmod_perl版では、
一部のレスポンスの悪いアプリがあるとPlatform全体が引きずられてしまっていた。


Plack + AnyEvent版では
携帯からリクエストされるとサーバー上のPlack::Server::AnyEvent::Preforkが処理をする。
SAPサーバーとのやりとりはCoro::AnyEventで行い、SAPサーバーへのリクエストをnon-Blocking化する事で、一部アプリが遅くても全体に影響を与えないようにした。
DBへのアクセスは内部API呼ばれたmod_perlが担当する。


いろいろ試した結果、Plackmod_perlを1台のサーバに同居させた。
Plack+AnyEventの負荷は無視できる。
PlackとInternal API間の通信は、HTTPで行う。
65台のアプリ用サーバが可動中


Tokyo TyrantQ4Mについて
Tokyo Tyrant
・「最近使ったアプリ」へのデータ格納に利用。
・書き込みが多い処理に最適。
・マスタ1台+スタンバイ1台で構成。


Q4M
・ライフサイクルイベントに利用。
OpenSocial v0.9仕様。
・ユーザーのアプリ登録/削除をSAPサーバーに対して、POST/GETで通知する処理に使用。


●コンテンツ配信サーバー
・三月上旬に公開しました。
・静的ファイルを代理配信、CDN的に使える。
WebDAVでアップロード。
・無料で利用可能。


●まとめ
ヒットすると、数千万〜数億PV/日のアクセスがくるため、対応するインフラの技術力が必要で、100台規模のサーバーを用意しているSAPもあるくらい大変な労力が必要だが、エンジニアにとって、大きなチャンスでもある。


●今後の予定
・Activity(重要なものが目立つように)。
・PCからアクセス可能な動作テスト環境を準備中。
・OpenSocoal0.9対応を夏までに完了予定。
・モバイルアプリ仕様の統一。


◎発表 その3
Inside MBGA Open Platform - GADGET SERVER -
発表者:hide-kさん

Denaの木村さんが、
モバゲーOpen Platformのガジェットサーバ周りについて
お話をしてくださいました。


●MBGA Open Platform概要
モバゲータウンとプラットフォームとして公開。
OpenSocial 0.9準拠。


●Gadgetサーバーの持つ役割
・携帯とSAPサーバーのリクエスト/レスポンスを中継する役割。
・ユーザーの認証機能を持つ。
・OAuth signitureを携帯リクエストから生成する。
・リクエストごとにAccess Tokenの発行をする
・レスポンスコンテンツに対しての整形を行う。


●Gadgetサーバーを「Hermit」と命名
Perl/PSGI/Plackを採用。
・Plaggableな構成を意識した。


PSGI/Plackを採用した理由
(1)必要なものは、Web Applicationではない
・Dispatcherが不要なので、Catalystよりも薄いものでよかった。
(2)すでに実装されたものがある。 => Plack::Handler::*や、Starman


PSGI/Plack
サーバー環境は、lighttpd + Plack::Server::FCGI

アクセス数は1サーバーあたり、300プロセス。
一日では、1サーバあたり、550万〜600万リクエストをさばいている。
ピーク時のリクエスト数は、1サーバの1時間あたり、36万〜38万リクエストをさばいている。
(うち、最大5秒かかるリクエストもあるので、もっと処理は可能。)
あと2倍のリクエストはこなせそう。


●Pluggable
Pluggerライクなプラグイン機構
=> Class::Triggerを利用
Pluggableな構成を採用した理由は、仕様変更が猛烈に多かった。
結果、拡張がしやすく、メンテナンスが楽で、テストもしやすくなった。
(Pluggableな構成をとる事で、多少のパフォーマンス劣化はあるかもしれないが、メリットのほうが大きかった。)


Plugin::Request, Plugin::Responseでリクエスト/レスポンスを加工。
機能ごとにプラグイン化すれば、機能追加やバグの検証なども修正すべき箇所が限定されて作業がしやすくなった。


●その他利用するCPANモジュール
Text::MicroTemplate => footer等
HTTP::MobileAgent
HTML::SticyQuery::DocomoUID
OAuth::Lite
HTML::filter::Callbacks
DBIx::DBHResolver
Log::Dispatch
Test::TCP


●その他
*Sandboxについて
・2009年11月に本番に先駆けて、Sandbox(Developper向け開発環境)を公開。
・開発環境=擬似モバゲータウン
・実機での登録が必要。
・PCでのアクセスも可能。
・近いうちに全開放予定。


CDN => 静的ファイルはデフォルトですべてCDNを通す(お代はDena持ち)


●実際にプロジェクトを通じてきつかった事
*スケジュール
・2009年8月1日にプロジェクト開始で、2009年11月24日リリースという予定で、全然期間がなかった。
・実際にコードを書き始めてのも2009年11月の初旬からだったが、短期間でリリースにこぎつけたのは、Plackのおかげだった。

*パフォーマンス
モリーよりもCPU使用率が問題となり、プロファイルを実施。
・Devel::NYTProfや、Unix::Getusageを使用。
Hyper-Threadingの設定がoffになっていたが、設定を変えることでcpuのパワーが2倍になった。


●よくわからない現象
lighttpdがやたらエラーを吐く現象。lighttpd 1.4.23にバージョンアップしたら解消した。


●現在抱える問題
*サーバー環境
FCGI => よくわからない部分が多い。Reverse Proxy(Starman)に変更する予定。
sslを今後使う可能性を考え、lighttpdを採用しているが、sslを今後も使わないので、フロントエンドいらないという結論。


*ネットワーク問題 => タイムアウト(5秒)設定があり、頻発すると自動メンテナンスモードになってしまう(アプリが使えなくなってしまう)。タイムアウト時間を伸ばすくらいしか対応策がない。
Amazon EC2が盛んに使われているけど、通信先が海外なのでタイムロスがどうしてもかかってしまう。早く日本初のクラウドサービスがでてくるといいね!。


●将来的に臨みたい事
スマートフォンや外部アプリケーションへの対応
・認証、認可をどうするかが今の検討課題。
・XAuthはクライアンとを信用しなければならない、どうするか?


OpenSocial 1.0にこれから対応していきたい。


*Template化
OpenSocial Templateを導入して、ユーザーがApiにアクセスしなくてもよくしたい。
・現状キャリア判定などは、アプリサーバーが各自に行っているが、出来ればプラットフォーム内部で解決したい。


●結論
Plackは実務で使えるレベル
・実際に動かさないとわからない問題もある。
・今のアーキテクチャから脱却したい!=> よりパートナーやユーザーが使いやすいものを使っていきたい。