ISUCON3の予選に参加してみました。
結果、一般枠10位で、無事予選突破、本戦に進めることになりました。わいわい。
ISUCON1は気付いたら終わってて、2は出ようと思ってたけどスケジュールの都合がつかず、今回が初参加になります。
チームメンバーは id:motemen, id:wtatsuru ダブルチーフ&ダブルタツルのダブルダブルチームです。チーム名は Third Party Cookies。はてなブログはサードパーティクッキー受け入れを推奨しています。
撮影 : hitode909
インフラはwtatsuruに任せ、アプリ周りの改修をmotemenと分担。分担と言っても思いついたことを思いついたままにやっていただけなので、もう少し戦略とか考えていくべきだった。事前準備も何もしてなかった。redbull買ったくらい。
以下、自分が何をしたかを適当に書きます。他のメンバーの方が頑張ってた。
markdown
外部プロセス呼び出してるので明らかにネックになってる。最初は ALTER TABLE して formatted_content カラムを追加、markdownを展開した結果を保存、起動スクリプトでも初期データをformatしておくという実装にした。
が、起動スクリプトが重くなると、ベンチマークが気軽にできないなーと思い直して、最終的には外部プロセスで実行しないように変更するのと、展開結果をmemcachedにキャッシュするだけに留めた。
クエリ改善
ORDER BY created_at DESC, id DESC
は完全に無駄。id は primary key なので 単に id DESC
に置き換えた。
recent の深いページの OFFSET の大きいクエリが重いので、id のみを引き、WHERE IN で * を引き直すことに。最初のクエリは id しか引かないことでインデックスで完結するのでクエリは増えるがトータルで速くなる。
セッション
users テーブルは通常のページでは id と username カラムしか表示されないし、それらの値は不変(変わるインターフェースが無いから)。だから users テーブルを引く必要は無い。session に id と username を格納するように書き換えた。
最後の方で、ベンチで FAIL しなければ何をしても良い戦略に切り替えて、session にストレージも使用しないようにして、cookie のvalueに単に id=1,name=onishi
という文字列を格納するようにした(ひどい)。
実際の運用でも、cookieのvalueにデータを格納する事は暗号化すればアリだと思ってる。
セッションでユーザーを復元しても、それは「ようこそ○○さん」の表示にしか使われない、といったことはウェブサービスでままある。表示に使うusernameはcookieに入れておいて、本当に必要になった時だけ DB を引く、といった戦略は実際のサービスでも有用だと思う。
プロファイリング
拙作、Devel::KYTProf は常時有効にしている。無駄なクエリが発行されてないかとかに注意しながら開発できす。これで stylesheets="/" とかは一瞬で気づけた。
carton exec plackup -s Starman -p 5000 -E prod -MDevel::KYTProf --workers 10 app.psgi
ちゃんとしたプロファイリングのためには Devel::NYTProf は必須ですね。
NYTPROF="sigexit=int" carton exec plackup -s Starman -p 5000 -E prod -MDevel::NYTProf --workers 10 app.psgi
みたいな感じでDevel::NYTProfでプロファイリング。PlackアプリのNYTProfでのプロファイリングは tokuhiromさんが昨日書いてたエントリに詳しい。勉強になります。Devel::NYTProf で Starlet/Starman (Plack) でうごくウェブアプリケーションのプロファイリングをおこなう方法まとめ - blog.64p.org
その他
ほかにもこまごまやったけど僕がやった中ではあんまり価値のある情報は無いです。チームメンバーのエントリ参照