こんにちは! onk です。
一昨日の 11/20 に RailsDevCon2010 にスピーカーとして参加してきました。場所はオラクル青山センターさん。
聞いていただいた皆さま,ありがとうございました。いやー,30 分も話すの初めてだったので緊張したw 実行委員の皆さまもお疲れさまでした!
プレゼン資料はこちら⇒とあるアプリの開発運用(トラブルシュート)
内容ですが,
ソーシャルならではの負荷分散、インフラ、ログ解析とかが聞けると夢が広がっていいかも。他セッションと絶対かぶらないし。大規模サービス作ろうとしている人にはありがたいと思います。
と @2celeb さんからリクエストがあったので,『聞くだけで運用した気になるソーシャルアプリ』を主題にしました。駆け足でしたが,伝えたいことは盛り込めたかなぁと思います。少しでも参考になれば幸いです。

sasata299タイトル画面ww #RailsDevCon
ikm一瞬見えたロゴがw #railsdevcon
sgtakeru@onk さんのセッション開始 #RailsDevCon
d6rkaiz#RailsDevCon とあるソーシャルアプリの開発運用 @onk さん
DiscoveryCoach3つ目のセッション、とあるアプリの運用開発。 (#railsdevcon live at http://ustre.am/qnNA)
ClockWorkStudioとあるソーシャルゲームの開発運用(トラブルシュート) #RailsDevCon
ikm意外と会場にソーシャルゲームを作った人が少ない #railsdevcon
oukayukaO・N・K! O・N・K!! #railsdevcon
話し始める前にソーシャルゲームを開発したことがある人に挙手してもらったんですがほとんど居ませんでした。遊んでる人で半分ぐらいだったかな。
ロゴはおなじみ http://to-a.ru/ ですね。名付け親は @youthk。

sgtakeruソーシャルアプリは、API利用、人口爆発、短納期 #RailsDevCon
DiscoveryCoachまずはソーシャルアプリのAPI利用の話 (#railsdevcon live at http://ustre.am/qnNA)
DiscoveryCoach開発はAPIを使った場合のデバックの仕方が肝。 (#railsdevcon live at http://ustre.am/qnNA)
ar1ハンゲームでけー #RailsDevCon つか、800万人いるのかドリコムのソーシャルゲー.
あ,p11 も p12 もアクティブユーザ数じゃなくて会員数です。念のため。適当にプレスリリースから拾ってきたので半年分ぐらい誤差があると思う。

cesare#RailsDevCon 「大安なのでリリース」w
ikm大安大事 #railsdevcon
agilekawabata大安でリリース #RailsDevCon
ar1大安なのでリリース(w #RailsDevCon
oukayukaソーシャルアプリは2ヶ月でリリースがデフォ #railsdevcon
sgtakeru大安でリリース&バージョンアップ #RailsDevCon
tyabe#RailsDevCon リリース日は大安
adzuki34「大安でリリース」 #RailsDevCon
hs9587#RailsDevCon 「とあるソーシャルアプリの開発運用」 大安なのでリリース
DiscoveryCoach2ヶ月でリリースは想定内。短納期をいかにこなすか。何を犠牲にして何を得るのか。。。が大事。 (#railsdevcon live at http://ustre.am/qnNA)
agilekawabata大安リリース駆動開発だな #RailsDevCon
ClockWorkStudio聴いたこともないgemがズラッと並んでた #RailsDevCon
ikmunicorn+nginx+rails3+ruby1.9.2など、今風の環境 #railsdevcon
oreradioドリコムさんもRedis使ってるのね。 #RailsDevCon
TrinityTミドルウェア、ことごとく最新だ。unicorn2, nginx0.7, Rails3, MySQL5.1, Ruby1.9.2, Redis.... やるなドリコム! #RailsDevCon
HexaRedis 使っているのか。 #RailsDevCon
d6rkaiz#RailsDevCon ドリコムさんでの環境一例 nginx+unicorn+mysql+memcached+redis+rails
「2ヶ月でリリースがデフォ」はさすがに言い過ぎっす……。
ミドルウェアは大体最新に合わせるようにしてますねー。「RailsConf 2010 に合わせてリリースされるだろう」と Rails3 beta で開発した挙句 rc4 の状態で本番投入したりとか,Passenger3 で地雷踏んだりとかしています(

ar1ドリコムのミドルウェア環境のversionはかなりあたらしいので揃えてるな。L5520 x2で32GBメモリの上に仮想化。8つくらいのVM #RailsDevCon
ar1#RailsDevCon リクエスト&レスポンスを確認しろ! HTTPのステータスコードをみろ!
cesare#RailsDevCon 「困ったら TCP まで降りる」基本ですなw
ikm困ったらリクエストとレスポンスを見る。TCPレイヤーで見るのが確実 #railsdevcon
DiscoveryCoachバグで3困ったらTCPレイヤまで降りてパケットを確認しよう。 (#railsdevcon live at http://ustre.am/qnNA)
sgtakeruデバックは、困ったら、request/resonseまでみる。TCPレイヤーまで降りてパケットを見る。 #RailsDevCon
arihhパケット監視マジ重要 #RailsDevCon
takaiTCPじゃなくてHTTPだよね
はい,HTTP でしたごめんなさい!
アプリの中から見ているだけだと oauth や jpmobile の挙動によく泣かされたので,API とやり取りするときは必ず WAF が処理する前の request を眺めるようにしています。
サーバ構成はあくまで基本構成で,本番は web がズラーっと横に並んだり cache や db の slave が並んだりします。

ar1#RailsDevCon Net::HTTPにloggerをしこむ net-http-spy. というかこれがrubyねた最初?
ClockWorkStudionet::httpにloggerをしこむnet-http-spy #RailsDevCon
TokyoIncidentsnet-http-spy #RailsDevCon
DiscoveryCoachかなり具体的ですごい。会場の文字入力のかちゃかちゃという音が今日最大かも。。ww (#railsdevcon live at http://ustre.am/qnNA)
ikmnet-http-spyでNet::HTTPにロガーを仕込む。超便利そう #railsdevcon
TrinityTnet-http-spy tcpflow #RailsDevCon
hs9587#RailsDevCon 「とあるソーシャルアプリの開発運用」 問題発見は request と response を見る、眺めてれば分かる事も多い。 net-http-spy Net::HTTP にログを仕込む
ar1#RailsDevCon tcpflowつかってんのか。。yumとかaptをみたり。gree行きのも見ると。。
d6rkaiz#RailsDevCon tcpflow // tcpdumpの保存しないバージョン
masaki925net-http-spy でTCPパケットロギングしてデバッグ #RailsDevCon
TokyoIncidentstcpflow #RailsDevCon
martinbtt's net-http-spy at master - GitHub ですね。外にアクセスしてるのが一目瞭然で便利なので,僕は .irbrc に
require "net-http-spy"
を書いています。
tcpflow は yum や apt で入れてください。ファイルに落としたいときってそんなに無いので flow で十分なんですよねー。

_shimadaタイトルに反して超実践的で参考になる (#railsdevcon live at http://bit.ly/a480k3
nog凄く具体的な話してるなー。 (#railsdevcon live at http://ustre.am/qnNA)
DiscoveryCoach巨大SNSのアプリだとスモールスタートできない。。。 (#railsdevcon live at http://ustre.am/qnNA)
nogRails1インスタンス200MB?多くね? (#railsdevcon live at http://ustre.am/qnNA)
ar1#RailsDevCon スモールスタートさせてくれない。1ヶ月で30万突破を視野にしておく。10万DAUで 1000万imp/day -> 230imp/s 。Railsは200MB workerだと かけ算で40G.
ar1#RailsDevCon m1.xlargeの限界は2300QPSくらい
ClockWorkStudio230imp/secだった場合の必要なマシンリソースの説明が具体的すぎてすげえ #RailsDevCon
tkawaスモールスタート機能(?)あるといいかも。招待制にするとかすればいいのかな? (#railsdevcon live at http://ustre.am/qnNA)
DiscoveryCoachマシンのスペックまでも。。。もう明日からはじめるソーシャルアプリ的な話ですね。 (#railsdevcon live at http://ustre.am/qnNA)
CPU 使用率はアプリによって違うだろうから,分かりやすくメモリ使用量で表現しています。150MB 超えることもあるので念のため 200 弱と言っておきました!

ikmデータ量の増加が著しいのでmaster/slave必須 #railsdevcon
sasata299ソーシャルゲームの規模感は凄いなぁー #RailsDevCon
ysakaki@onk の発表実践的で凄いな。こういう話がもっと聞きたい! #RailsDevCon
TokyoIncidentsこのスライドは絶対復習したい #RailsDevCon
ar1#RailsDevCon マイミク村. ともだちコレクションみたいなもの。質問を全て保存するのでしんどい。DBをなんとかする。
shinodoggソーシャルゲームのキャパシティプランニングの話。コレは参考になるなぁ。こういうのを大安の日ドリブンみたいなノリで継続してリリースし続けるのはカッコイイ。 #railsdevcon
DiscoveryCoachDBのmaster/slave分散を考える。 (#railsdevcon live at http://ustre.am/qnNA)
johnsmith0707スケールアウトか。puppetとかもあるように、最近はほんとにスケーラビリティの高さが求められるよね。 #RailsDevCon
ikmmaster/slaveはMasochism #railsdevcon
ar1#RailsDevCon master/slave分散。参照系だったらslaveを見にいく、updateはmasterに、とかはアプリで書く。ライブラリつかってない
_shimadaActiveRecordでmaster/slave分散は難しくない (#railsdevcon live at http://bit.ly/a480k3
DB 切り替えてる部分はどれも 100 行無いぐらいなので読んでみるといいです。使い方じゃなくて中身に言及している記事が増えると世界が面白くなる。

ar1#RailsDevCon JOINできないから、RDB関連は消す。habtmとか。
junyaゲームはEventually Consistentだとまずいデータがほとんどだから面倒くさそうだ。 #RailsDevCon
DiscoveryCoach更新系をmasterに、参照系をslaveにまわしてみたが、ゲームのアプリは更新系が多くて限界がくる。例:体力減る。 (#railsdevcon live at http://ustre.am/qnNA)
TrinityTマスタDBをテーブルごとに分割→has_manyやbelogs_toが使えなくなる→関連はAP側で実装か〜。 凄い試行錯誤だったんだろうな。 #RailsDevCon
すみません見栄張りました。分割はカテゴリごとなので,そのカテゴリ内では JOIN 可能です。なので自分でクエリ投げ直す処理はそんなに発生しないですね。

ar1#RailsDevCon rails3のshardingにはoctopus. 最近はいいハードなのでscaleupで対応
ikmshardingはdb-charmer, data_fabric, octopus #railsdevcon
hs9587#RailsDevCon 「とあるソーシャルアプリの開発運用」 Sharding 、DB のレプリケーションと分割、そういう gem もある
ar1#RailsDevCon MongoDBにするのは悩み中。AR捨てるのが..
sasata299master-slaveはmasochizm、shardingはoctopusを使ってやってるらしい #RailsDevCon
_shimadaテストデータはfakerで作成 (#railsdevcon live at http://bit.ly/a480k3
agilekawabataテストデータ生成に便利なgem faker #RailsDevCon
oukayuka負荷テスト用のダミーデータを作ってくれるgem > faker #railsdevcon
ClockWorkStudio50万ユーザが3ヶ月遊んだ想定のデータを作成した上でのアクセス負荷試験 #RailsDevCon
DiscoveryCoach負荷テストは50万ユーザが3ヶ月遊んだ想定のデータを作成してm本番想定と同じアクセス負荷をかけて行う。 (#railsdevcon live at http://ustre.am/qnNA)
RailsDevCon負荷テストのためにリリース前に50万ユーザが3ヶ月遊んだ想定のデータを突っ込む。 #RailsDevCon
sasata299"MongoDBを使えば解決するんじゃないか”w #RailsDevCon
ar1#RailsDevCon jmeter + fakerでデータ生成 で、負荷テスト.スループット,DiskIO、コネクション数に注目(webとdb)。
スケールアップで対応できちゃったので,octopus まだ使ってません。でも今使うならコレかなぁと考えています。
MongoDB は試してみたいんですが,Mongo 脳になって綺麗な設計が出来るようになるまでにまた 3 アプリぐらいかかるんだろうな。
負荷テストと監視については YAPC::Asia 2010 での myfinder さんの発表が良かったです。myfinder's blog: YAPC::Asia 2010 でソーシャルアプリのシステム監視運用について Talk してきました

DiscoveryCoach基本、最速でユーザにレスポンスを返す。後は裏で非同期。 (#railsdevcon live at http://ustre.am/qnNA)
ikmTOPへのアクセスをトリガーにして各種ページの準備を事前に実行する、とか #railsdevcon

nogメモ:Resque (#railsdevcon live at http://ustre.am/qnNA)
_shimada非同期処理は Resque。 管理画面あり (#railsdevcon live at http://bit.ly/a480k3
sasata299Resqueで非同期処理をガンガン使ってるみたい。マイページ開いたときにはデータが出来上がってる想定みたいだけど間に合わなかったときはどうするんだろう #RailsDevCon
ar1#RailsDevCon 5秒ルールのせいで、非同期を徹底活用。Resque gemをつかっている。管理画面がいい。バッチ処理も簡単。
ClockWorkStudio非同期実行のgem、rescue。管理画面が便利らしい #RailsDevCon
d6rkaiz#RailsDevCon 非同期で扱うためのgemにresque
ar1#RailsDevCon まとめた処理にactiverecord-importを使っている。
agilekawabata一括insert gem activerecord-import #RailsDevCon
sasata299activerecord-import使うとバルクインサートが楽?へー #RailsDevCon
ClockWorkStudioactiverecord-importでBULK INSERT!! #RailsDevCon
_shimadaResque Scheduler。毎回script/runnerを叩かなくていい (#railsdevcon live at http://bit.ly/a480k3
DiscoveryCoachゆーざーが100万人くらいになると「手抜きかな」と思いながら創った部分が必ず「ボトルネック (#railsdevcon live at http://ustre.am/qnNA)
ikmシビアだ #railsdevcon
oreradioユーザ数数万程度を想定しているコードは全てNG #RailsDevCon
n0tshttps://github.com/zdennis/activerecord-import RT @sasata299: activerecord-import使うとバルクインサートが楽?へー #RailsDevCon
TrinityT「ユーザ数、数万で想定しているコードは全てNG」→バッチで1ユーザあたり1秒かかってたら、一日86400ユーザ分しか処理できない! #RailsDevCon
d6rkaiz#RailsDevCon ユーザ数数万程度のコードは全てNG
そういえば Rails3 から route が Rack に載ったので,sinatra アプリである Resque の管理画面も一緒に動かせるようになりましたね。

ar1#RailsDevCon GAEの設計の意味がわかってくる(w
ikm巨大SNSのユーザ数で自分の技術力が向上 #railsdevcon
DiscoveryCoach巨大SNSから流れてくるユーザ数はエンジニアの甘えを許さない。 (#railsdevcon live at http://ustre.am/qnNA)
junyaURL設計図って rake routes で間に合う気もする #RailsDevCon
_shimada開発中はER図とURL設計書だけで進める (#railsdevcon live at http://bit.ly/a480k3
ysakaki迷ったらRailsっぽく書く。素晴らしい。 #RailsDevCon
ar1#RailsDevCon PDCAを早くするためドキュメントを削減。図の多用。Railsっぽいコードから外れないようなコード。
hs9587#RailsDevCon 「とあるソーシャルアプリの開発運用」 迷う時間を最小限にする: Railsぽいかどうかを考える
ikmRESTfulっていう前提はあるかなぁ RT @junya: URL設計図って rake routes で間に合う気もする #RailsDevCon
nogソーシャルゲームもこういう観点で見ると面白そうだよなー (#railsdevcon live at http://ustre.am/qnNA)
tkawa「正しくwebアプリを作る」それを「正しく」って言い切るのもなぁw (#railsdevcon live at http://ustre.am/qnNA)
johnsmith0707ペアプロで迷う時間を最小限に #RailsDevCon
DiscoveryCoach短納期に対応するひとつの方法。迷う時間を少なくする。=ペアプロ。そしてRailsっぽいかどうかを思考の指針できるように常に考える。 (#railsdevcon live at http://ustre.am/qnNA)
shinodoggドキュメンテーションなくても、RailsっぽいアプリならER図見りゃわかるし、RestっぽいインタフェースならURL見れば分かる。迷ったらRailsっぽくなってるかどうか。くぅー。シビれる。。 #railsdevcon
負荷対策をすればするほど GAE に近づいていっている気がしたので,なるほどあの制限は正しいなと思えるようになりました。一度しっかり RDBMS で戦うと NoSQL や GAE を使うための意識改革が出来るんじゃないかと思います。
URL 設計書は確かに rake routes と中身は同じなんですが,チーム全員で URL を考えるときに 200 行を超える routes.rb だけだと見通しが悪いので,はじめは Excel でやっています。設計が終わって一通り generate し終えたら routes.rb だけ管理で十分ですねー。

ar1#RailsDevCon Plan (常にかんがえる) Check (かってにデータがあつまってくる) 速度をあげる。
ちなみに,天井からぶら下がってるこのモニタのシステムは『グリゴリ』と言います。旧約聖書偽典『エノク書』 (みんな大好きイーノックさん) に出る堕天使の一団。「見張る者」という意味です。
「ユーザーの動きに応じて、PDCAサイクルを異様なほどの超高速で回すのが、ソーシャルゲームの運営だ」 といった話も紹介しようと思ったんですが残り時間が少なかったのでカット。

ar1#RailsDevCon ログの集約、収集にscribeを使ってる!
ikmscribe+messagepack #railsdevcon
ar1#RailsDevCon scribeにつっこむときにmessage-packで圧縮考えてる。
hs9587#RailsDevCon 「とあるソーシャルアプリの開発運用」 scribe 分散した多数のサーバのログの集約が大変
d6rkaiz#RailsDevCon 一日3gbのlogを見るために scribe -> messagepack にするか検討中?
sasata299複数台に分かれたログの収集はscribe使ってる http://d.hatena.ne.jp/perezvon/20100110/1263120529 #RailsDevCon
masaki925ログ転送ライブラリ scribe; scribeサーバに送っておけばscribe 間で転送・エラーハンドリングしてくれる #RailsDevCon
長々と失礼しました。また来年も発表できるよう頑張ります!!
Fixture suck! と言われて久しいですね。こんにちは! onk です。
最近は Rails 3.0 でソーシャルアプリを作っています。で,BDD に RSpec 2.0 & FactoryGirl を使い出したので FactoryGirl についてご紹介。
まず,FactoryGirl は ActiveRecord に依存しています。factory の定義は AR のモデル単位。
Factory.define :onk, :class => User do |user|
user.name "onk"
user.email "onk@drecom.co.jp"
end
たとえばこんな感じですね。
定義した factory を使うときは
Factory.create(:onk)
#=> #<User id: 1, name: "onk", email: "onk@drecom.co.jp", created_at: "2010-05-27 18:59:40", updated_at: "2010-05-27 18:59:40">
とか
Factory.build(:onk)
#=> #<User id: nil, name: "onk", email: "onk@drecom.co.jp", created_at: nil, updated_at: nil>
とかになります。
create だとデータを保存してオブジェクトを返します。build は保存せずに返します。 User.new(params[:user]) みたいなものだと思えば OK。あと Hash だけ欲しいときは
Factory.attributes_for(:onk)
#=> {:email=>"onk@drecom.co.jp", :name=>"onk"}
とします。
なお,factory の定義名=クラス名である場合は :class が省略できます。
Factory.define(:user) do |user|
user.name "名無しさん"
end
使うときもデフォルトは create なので
Factory(:user)
で呼び出せます。
Factory.defineFactory.createFactory.buildFactory.attributes_for他にも stub とかありますが,とりあえず以上だけ覚えておけば Fixture っぽく使えるかと思います。
ひとつだけ注意点。define した factory は全て Factory.factories に詰められてるだけなので,全 model で共通の名前空間になっています。 名前の付け方には注意してください。model 名で prefix, suffix を付けると分かりやすいですね。
+-------------------+
| User |
+-------------------+
| PK id int |
| name string |
+-------------------+
| (user.id = post.user_id)
+-------------------+
| Post |
+-------------------+
| PK id int |
| FK user_id int |
| body string |
+-------------------+
のような関連を表したいときは factory 定義の中で保存してしまえば良いです。
まずは has_one 関連の場合。
Factory.define :post do |p|
p.body "オマエモナー"
end
Factory.define :user do |u|
u.name "名無しさん"
u.post Factory(:post)
end
で,:user を生成すると
u = Factory :user
#=> #<User id: 1, name: "名無しさん", email: "sage", created_at: "2010-05-27 19:19:37", updated_at: "2010-05-27 19:19:37">
u.post
#=> #<Post id: 1, user_id: 1, body: "オマエモナー", created_at: "2010-05-27 19:19:21", updated_at: "2010-05-27 19:19:37">
となり,見事に関連が張られています。
ちなみに :user と :post を書く順番を逆にすると
ArgumentError: No such factory: post
と怒られてしまいますので,読み込み順を深く考えたくない場合は {} で囲って遅延評価にしておきます。
Factory.define :user do |u|
u.name "名無しさん"
u.post {Factory(:post)}
end
has_many の場合は配列で定義します。
Factory.define :user do |u|
u.name "名無しさん"
u.posts {[Factory(:post), Factory(:post), Factory(:post)]}
end
u = Factory :user
u.posts.size #=> 3
関連を非常にすっきり書けますね。これが FactoryGirl の魅力の一つです。
関連を記述しているとき,validate があると結構厄介です。先ほどの
+-------------------+
| User |
+-------------------+
| PK id int |
| name string |
+-------------------+
| (user.id = post.user_id)
+-------------------+
| Post |
+-------------------+
| PK id int |
| FK user_id int |
| body string |
+-------------------+
で,Post#user_id に
validates :user_id, :presence => true # 要は not_nil
をかけてるとしましょう。ありがちですね。
先ほどのままの factory 定義
Factory.define :user do |u|
u.name "名無しさん"
u.posts {[Factory(:post)]}
end
Factory.define :post do |p|
p.body "オマエモナー"
end
では,:user を保存するより先に :post を保存することになります。このとき,まだ user_id が入っていないので validation に撥ねられます。
Factory :user
#=> ActiveRecord::RecordInvalid: Validation failed: User can't be blank
factory_girl/proxy/create.rb を読んでみると
class Factory
class Proxy #:nodoc:
class Create < Build #:nodoc:
def result
run_callbacks(:after_build)
@instance.save!
run_callbacks(:after_create)
@instance
end
end
end
end
となっています。つまり :after_build,:after_create で処理を挟むことができます。
これを使えば,validation に引っかかるようなモデルも上手く書くことができますね。
Factory.define :user do |u|
u.name "名無しさん"
u.after_create do |user|
user.posts = [Factory(:post, :user_id => user.id)]
end
end
Factory.define :post do |p|
p.body "オマエモナー"
end
u = Factory :user
#=> #<User id: 1, name: "名無しさん", email: nil, created_at: "2010-05-27 19:42:41", updated_at: "2010-05-27 19:42:41">
u.posts
#=> [#<Post id: 1, user_id: 1, body: "オマエモナー", created_at: "2010-05-27 19:42:41", updated_at: "2010-05-27 19:42:41">]
はい,綺麗に書けました。
あ,Factory(:post, :user_id => user.id) みたいに create 時に外から attribute を渡すこともできます。なので「ちょこっとだけ違うオブジェクトを作りたい」とか言うときはテストの中でさらっと書いちゃえば良いと思います。
Factory(:user, :name => "名も無き冒険者")
#=> #<User id: 2, name: "名も無き冒険者", email: nil, created_at: "2010-05-27 19:44:29", updated_at: "2010-05-27 19:44:29">
unique 制約かけたいカラムってありますよね。そんなの相手に愚直に factory を数十個作るなんてもったいないです。sequence を使いましょう。
Factory.sequence(:google) do |n|
"go" + "o" * n + "gle"
end
Factory.next(:google) #=> "google"
Factory.next(:google) #=> "gooogle"
Factory.next(:google) #=> "goooogle"
Factory.next(:google) #=> "gooooogle"
まぁ呼ぶたびにインクリメントするだけなので普通に n 返せば良いです(笑)
Factory.sequence :name do |n|
"user_#{n}"
end
Factory.define :user, :class => :User do |u|
u.name {Factory.next(:name)}
end
と sequence と next を使うように定義しておけば
Factory.create(:user)
#=> <User id: 1, name: "user_1", email: nil, created_at: "2010-05-27 19:45:15", updated_at: "2010-05-27 19:45:15">
Factory.create(:user)
#=> <User id: 2, name: "user_2", email: nil, created_at: "2010-05-27 19:45:16", updated_at: "2010-05-27 19:45:16">
となります。
Factory.next を {} と遅延評価にするのを忘れると,常に "user_1" が入っちゃうので気をつけて。
factory の継承もサポートしています。
Factory.define :user do |u|
u.name "名無しさん"
u.email "sage"
end
Factory.define(:admin_user, :parent => :user) do |u|
u.name "名無しさん@FOX★"
end
Factory :admin_user
#=> #<User id: 1, name: "名無しさん@FOX★", email: "sage", created_at: "2010-05-27 19:45:35", updated_at: "2010-05-27 19:45:35">
email が継承されていますね。sequence と parent を上手く使いこなせば,Factory.define はそんなに書かなくても良いはずです。Fixture を使っていたときにカオスになったのを思い出して,最低限の記述にすることを心がけましょう。
sequence や parent で見えてきましたね。Fixture と FactoryGirl では概念がまったく違います。Fixture にはオブジェクトの値を直接記述していました。しかし,FactoryGirl で定義するものはオブジェクトではなく雛型です。使うときに,雛型からオブジェクトを好きなだけ作れば良いのです。
冒頭で記述したような :onk というオブジェクトを定義するのは大きな誤り。オブジェクトを定義してしまうと Fixture と変わらず,管理しづらいものができ上がると感じています。雛型名は単なる :user ですね。他に何か定義するなら上記のような :admin_user や,post の有無で :posted_user を作る場合等がありそうです。
個人的にはなんとなく STI っぽいなと感じました。まぁ model のなかで class 作ってるようなモノなので。
雛型だと見切ったら,FactoryGirl と faker を同時に使うと非常に強力なことにも気づけるかと思います。
Factory.define :user do |u|
u.name {Faker::Name.name}
u.email {Faker::Internet.email}
end
Factory :user
#=> #<User id: 1, name: "Garland Keebler", email: "baron@wolff.ca", created_at: "2010-05-27 19:57:09", updated_at: "2010-05-27 19:57:09">
Factory :user
#=> #<User id: 2, name: "Marlee Mosciski Jr.", email: "samanta@emard.uk", created_at: "2010-05-27 19:57:10", updated_at: "2010-05-27 19:57:10">
Factory :user
#=> #<User id: 3, name: "Providenci Fisher", email: "madie_boyer@kochgleichner.us", created_at: "2010-05-27 19:57:11", updated_at: "2010-05-27 19:57:11">
Fixture からの解放は,単に関連記述を簡略化するだけではありません。性質の違う雛型を性質名で定義し,使うときには雛型をもとに好きなようにオブジェクトを作る。それが FactoryGirl の素晴らしい点だと僕は理解しています。
こんにちは! onk です。
SAPさんが各社とも「ソーシャルアプリは負荷対策が大事」って言っていますね。弊社でも mixi アプリ(PC),mixi アプリモバイルをリリースしたときはお祭り状態だったので,ふりかえりも兼ねて MySQL のボトルネックを調べる方法を書いてみました。(幸い,モバゲーオープンゲームのリリース時はこれらの経験が役に立ったので何ともなかったです)
といっても 9 割方
辺りなんですけどねー。
まず,ボトルネックを調べるときは下の層から上がっていくのが基本です。たぶん。
なので ssh でサーバに入って (LoadAverage 300 ぐらいまでならなんとか入れますね) 以下のコマンドをよく叩きます。
top現在稼動しているプロセスの一覧と,システム情報の概要が表示されるプログラム。
見るのは主に
と,これらが異常なプロセス。
たとえば swap だと,正常なときは
Swap: 7879872k total, 764k used, 7879108k free, 3589852k cached
ですが,異常に減っているときは
Swap: 7879872k total, 2529080k used, 5350792k free, 1574320k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
26945 mysql 20 0 7681m 6.0g 5080 S 37 77.2 17214:10 /usr/local/mysql/libexec/mysqld
のようになります。明らかに mysql がメモリ食い潰してますね。free や ps でも確認出来ますが,どのプロセスが悪いのか見渡しやすいので,僕は top が好きです。
vmstatこれもシステム情報を表示するプログラムです。
あたりを確認します。
たとえば CPU IO wait が異常なときは
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
r b swpd free buff cache si so bi bo in cs us sy id wa
0 11 20092 281480 12 7671592 0 0 27820 42 1967 2557 3 3 41 52
0 12 20092 284492 12 7668020 0 0 26512 1 1812 2222 2 3 47 48
0 13 20092 281188 12 7671080 0 0 33144 0 1890 2258 2 2 40 56
0 13 20092 277208 12 7674300 0 0 24612 0 1722 2000 2 1 38 59
0 24 20092 283364 12 7665688 0 0 24304 0 1871 2287 2 2 30 66
2 21 20092 284912 12 7661960 0 0 31688 30 1714 2130 3 3 35 60
となります。
大抵の場合,以上の 2 コマンドで原因となっているプロセスを特定できるので,新機能のリリース時は 2 画面開いて
top -d 5vmstat 5として見張っています。
大概,インデックスの張り忘れです。インデックスさえ張っておけば一瞬で終わるはずの WHERE 句や ORDER 句を,必死に CPU が計算しています。
最初はデータ量が少なくて気づかないかもしれないけど,次第に CPU 使用率が 100% に限りなく近づいて……。
varchar カラムに対して int を検索条件にする場合は INDEX が使われないので注意してください。MySQL は文字列の型に対して where hoge = 1 と絞り込むとき,'01' や '1.00' の行もマッチします。つまり INDEX は使えず,全件走査となります。
ソーシャルアプリでは opensocial_owner_id が文字列なのでコレやりがちなんですよね。さすがにすぐ気づくとは思いますが(笑)
データ量に対して,メモリの割り当てが少ない場合とか。
show table status;
したときの Data_length + Index_length と key_buffer_size や innodb_buffer_pool_size を見直してみてください。せめて Index だけでもメモリに載せてあげたいので。
ディスクの読み書きはメモリの読み書きの 10 万倍遅いです。ディスクアクセスは 1 回につき 5ms 程度かかるので,秒間 200 回しかアクセスできません。
1 回のクエリで 4 回ディスクへのアクセスが発生し,1 ページ表示するのに 5 回クエリを投げるとすると秒間 10 PV しか耐えられないことになります。1 ユーザあたり 150 PV/day,ピーク時に平均の 2 倍になる場合で 2,500 UU/day が限界な感じですね。これが全てメモリに載っていれば 5 億人までいけます。
MySQL の設定ではなくクエリが原因だと判断したら,実行中のクエリを確認します。
innotopshow processlistmprofileの 3 パターンかな。
InnoDB を使ってるときはぜひ。innotop - Project Hosting on Google Code
僕が注意しているのは
ですね。
トランザクションが重い場合,Query List には「COMMIT;」しか表示されなかったりするので注意してください。
show processlistinnotop や mytop で実行中のクエリのリストが見えるんですが,これらを入れていない場合は show processlist; で確認します。
クエリを全て Info カラムに出力したいときは
show full processlist;
Kazuho@Cybozu Labs: MySQL のボトルネックを統計的に監視・解析する方法
show processlist を 1,000 回実行し,どのクエリが何回表示されたかの統計を取ってくれます。何から潰すべきなのかの判断に迷ったらとりあえず統計取りましょう。
奥さんも書いてますが,定期的に実行してログを残しておくと,ユーザの動向と DB の使われ方の変遷が見えてきてサーバ増強計画を作りやすいですね。
……思ってたより長くなったので次回 EXPLAIN 編に続きます。乞うご期待!
こんにちは!onk です。
第50回PHP勉強会@関東 に参加してきました。会場は 株式会社コンテンツワン さん。50人超のメンバーを入れられる会場って限られてるのですごく助かります。ありがとうございました!
以下,当日のメモです。
mixi アプリの概要説明。技術的な説明の部分はほぼ mixi Developer Center のままかな。
流行るアプリの例として弊社の ハッピーアクアリウム を紹介いただきました。ありがとうございます^^
mixi アプリの流行るポイント 4 つ
はすごく分かりやすい指標。合わせて mixi のソーシャルグラフ (他社と違いバーチャルグラフ化していないリアルな友達) の健全性を保つことに言及されていたのが印象に残りました。
僕らは既に mixi / モバゲーに対してアプリを提供しているので,この辺は実装済みですね。開発時はほとんどソーシャルアプリという意識はないです。
PC と mobile で同じテンプレートを使うのを断念されてましたが,ちょこっと js で加工してあげれば HTML 断片返さなくても大丈夫じゃないかな。
カヤックさんの mist.js が参考になると思う。
まぁ実際は PC と mobile では情報量も変わるしページ遷移も変えるしで,とりあえず PC でも操作可能にしておくか程度にしか使えないんだけど。
超共感した!!!!
さすがに LA 4 桁はまだお目にかかったことがないなぁw 画像生成怖いっす><
「愛され系ゆるふわコーディング」の重要性はホントに声を大にして言いたいですね。
他サービスの API が落ちているときに
のいずれかはやっておきましょう,アプリとして想定しているエラーのはずなので。後でサービス落ちたりユーザの問い合わせが爆発したりと泣きを見ます。
もうホント正しく作るっていうそれだけなんだけどね……。甘えが残っているとそこがボトルネックとなるのを日々実感してます。
LT しました! 資料はこちら → ハッピーアクアリウム裏話 (2010/02/22@第50回PHP勉強会)
懇親会ではだいたい @cloned と @cocoitiban,@weboo と話してました。DeNA や mixi との NDA 気にしなくて良いメンツだと話しやすくていっすねw
モバゲーの API についてとか,各コンテナに対して絵文字をどう返すかとか,OAuth 署名の signature についてとか。SAP や Container のエンジニア同士で情報交換出来るのはとても助かるなー。
EC2 どうよ?という話もしたんだけど,正直 200msec 程度の遅延はモバイルだとそもそも回線が不安定なため気にならないかな。サービス投入直後の「どんだけ人が来るか読めない」段階ではクラウドを選択肢に入れない理由がない。伸びが予想出来るようになったら自社サーバに移せば良いです。
というわけで普段からスケールアウト可能な作りにしておくのがソーシャルアプリでは必須。
でも数十万ユーザ&初めの数ヶ月なら,数台でなんとかなります(
50 回も勉強会を続けるって強いなぁ。PHP 界隈元気ですねー。Symfony 2.0 の楽しげな話も聞こえてきました。
あと,OpenSocial への期待も大きいですね。
cloned さんの
過去のファミコンのような魅力的なプラットフォームなので、同じような感じのアプリがあるからとたじろぐのではなく「うちのはここが良い」というアプリをどんどん開発して公開するのがよろしいと思う。あれだけ素晴らしいドラゴンクエストとファイナルファンタジーがあったにも関わらずたくさんの後続のRPGがヒットして今でも愛されているように。
という発言はとても共感。ホントに 10 年に 1 度の面白い時代なので,みんなで盛り上げていきたいと感じてます。