More Related Content Similar to gumiStudy#1 ソーシャルアプリにおけるKVSの利用事例 (20) gumiStudy#1 ソーシャルアプリにおけるKVSの利用事例2. 自己紹介
• 株式会社gumi CTO
• Twitter: horiuchi
• 10年くらいウェブアプリ作ってます。
– Perl 10年、Python 1年
• ゲームが好きです。
– モンハン3予約しました!
• ランニング、筋トレにはまってます。
4. ソーシャルゲーム x ソーシャルライフ
ソーシャルライフ系 ソーシャルゲーム系
・空飛ぶ ・DeNA Rekoo 650万
→マイミク通信簿 340万 →怪盗ロワイヤル
幕末英雄伝→サンシャイン牧場
ファンクラブ
250万 キャバウォーズ460万
同級生掲示板 刑事ハードボイルド
・ ウノウ Rakoo 380万
現在開発中×2
卒業アルバム
→まちつく 270万
→みんなの農園
同級生を探せ 占い診断系×40+
・ ベクター 190万 160万
→恋する私の王子様→みんなの動物広場
150万 140万
サポートツール系
・ GPS連動アド ・ Facebook connect
・ リワードプラス(アドウェイズ) ・ mixi connect
・ poncan(ドリコム) ・ connect with twitter
・ gree connect
5. ソーシャルライフ
ファンクラブ 220,000人
同級生掲示板 520,000人
卒業アルバム おとなver. 300,000人
同級生をさがせ! 120,000人
6. 占い、診断系アプリ
SM診断〜あなたの本性暴きます O型度判定〜う〜んO型かなぁ?
浮気性チェック! 2人のラブラブ度診断
その愛本物?ニセモノ? 恋の成就度診断
犬タイプvs猫タイプ のだめカンタービレ進級試験初級
草食系 vs 肉食系 戦国雑学王決定戦★立志編
ザ★おバカ検定 のだめマエストロコンクール
むっつり度ちぇ〜っく!! ノーマル?orアブノーマル?
A型度判定〜本当にA型ですか?
のだめカンタービレ進級試験中級
常識・非常識〜あなた常識人?
のだめカンタービレ進級試験上級
KY診断〜空気読めてる?
戦国クイズ王全国ランキング
ナルシスト★診断
モテ↑非モテ↓診断
B型度判定〜ジーマーで型B?
じじばば検定〜若さ保ってる?
フリ派?フラれ派?
合計 約600万ユーザー
AB型度判定〜ABですが何か?
7. ソーシャルゲーム
• 2010年2月 幕末英雄伝 670,000人
• 2010年3月 キャバウォーズ 1,320,000人
• 2010年4月 刑事ハードボイルド 600,000人
• 2010年5,6,7月 多プラットフォーム展開
• 2010年8月 ハッピー☆モデル 70,000人
12. ユーザー認証
• Oauth signagureで身元保証
• QueryStringからユーザーID取得
– opensocial_owner_id
GET /m/?opensocial_app_id=
1234&opensocial_viewer_id
=5678&opensocial_owner_id=5678
13. APIが用意されている
• PeopleAPI
– ユーザー情報、友達情報を取得
• ActivityAPI
– ユーザーの行動履歴を更新
• PaymentAPI
– 課金を行う
• 招待を送れる仕組み
• 位置情報を送信する仕組み
• ひと言を送信する仕組み
17. なぜDBがボトルネックになるの?
●
Writeのスケールが難しい
●
テーブル毎にDBを分けたり
●
テーブル自体を分割したり
●
SQLによっては時間がかかる
●
たくさんの行を一度に読むようなSQL
●
大きいテーブル同士をjoinするようなSQL
18. 解決策は?
• 遅いクエリの見直し
– 主キーによる参照を意識する
– ManyToManyは基本使わない
– Filterもあまり使わない
– Joinもほとんど使わない
• テーブル設計の見直し
– 更新の多いカラムは別テーブルにする
21. gumiで活用しているKVS
• Memcached (Readを減らす)
– オンメモリなハッシュテーブル
– スケーラブル
– サーバを再起動するとデータは消える
– Django標準機能で簡単に使える
●
TokyoTyrant (Read Writeを減らす)
– モダンなDBMでデータの永続性あり
– MySQLより高速に読み書きできる
●
読み書き20000qpsくらい
23. キャッシュ実装例
def get_player(id):
"""
idからプレイヤーインスタンスを取得
"""
path = "/player/"+str(id)
player = cache.get(path, None)
if player is None: # キャッシュに存在しない
try:
player = Player.objects.get(id=id)
cache.set(path, player) # インスタンスをsetできる
except Player.DoesNotExist:
player = None
return player
26. まとめ
memcached + TokyoTyrant
でD B のボトルネックをすっきり解消!
29. 人材絶賛募集してます!
Twitter: horiuchi
Mail: horiuchi@gu3.co.jp