ISUCON5予選に「railsへの執着はもはや煩悩の域であり、開発者一同は瞑想したほうがいいと思います。 」チームで参加してきた #isucon

学生枠で出場した去年に引き続き、今年は新卒社員になった@cnosuke@rkmathiと僕@k0kubunの3人でISUCON5予選に出場した。
僕らが最後に確認できたスコアは11045で、その時のスクショだと2日目の16位という感じで、予選通過はなりませんでした。

id:rkmathiの記事: http://rkmathi.hatenablog.com/entry/2015/09/28/004734

戦略

最初にコードは読まず、nginxのアクセスログをパースして集計する奴とnewrelicを使ってベンチ中最も時間を使っているエンドポイントを特定し、そのエンドポイントの中でどこが遅いかはrack-lineprofで把握してそこだけ読んで潰していく感じでやった。
去年の感じだと予選はいきなりキャッシュとか入れなくても落ちついて普通のチューニングをしていれば突破できると思っていたので、地道にSQLのチューニングをしていた。

僕らのチームがやったこと

時系列で並べるのが好きなのでそれで書く。
cnosukeがインフラレイヤーをやって、rkmathiがMySQLのログ集計とかインデックス直しをやって、僕がクエリ変形させたりひたすらN+1を潰すのをやっていた。
他は思いついた奴を出しあって手があいてる人がやる感じだった。

score やったこと
200 Rubyの初期状態(大体)
800 nginxで静的ファイル配信
926 relationsのINSERTをone < another保証にしてクエリの条件減らした。created_atのソートを全てidにした。
1192 footprintsにインデックスを貼った
1264 InnoDBのバッファのサイズを上げた
2947 relationsのoneとanotherにインデックス貼った。セッションのクッキーストアの暗号化をやめた。
6202 "/" へのリクエスト用にis_friend?のN+1用preloader (JOINではなくクエリ2つで引く)を書いた。entriesのレスポンスをRedisにキャッシュするようにした。
9557 LIMIT 1000を10個に絞るクエリ2つを両方LIMIT 10で引き、commentsのSELECTのrowsが減るインデックスを貼り、Redisのチューニングをした
9610 firstしてる系にLIMIT 1を付加
10194 friend idsを引くN+1をなんとかした
7200 再起動しただけで点数が減った
7963 N+1になるget_userの汎用的なpreloaderを書いて適用
8402 ベンチを回す度に点数が回復していた
10000 friend idsを引くクエリをRedisのsetに変えた(けどこの辺でボトルネックがIOになっていて、期待よりスコアが伸びていない)
11045 遅いエンドポイントのビューの中のget_userとかのN+1を潰した。

最初に10000点まで行くのは結構早くて順調だったんだけど、RedisとMySQLのウォームアップがちゃんと書けず、CPUもメモリも使いきらない状態のまま提出となった。
この辺の経験不足が敗因なのかなあと思っているのと、正直このラインまでやれば予選抜けられると思っていたので、レベルが上がってるような気もした。

感想

めちゃくちゃ楽しかったし、ずっと集中しててすごい疲れた。去年は学生枠でギリギリ本戦に出してもらった感じだったけど、今年は去年よりちゃんとチームで連携してスコアが上げられて、メンバーの成長が感じられてよかった。
今年結構テンプレートエンジン周りを触ってて、その辺練習の時は最適化とかやってて今回の問題でも直せるところあるなと思ったけど、本番ではそのレイヤーにボトルネックが移せなかったのが悔しかった。

次から次へと直すところが出てくる面白い問題で、出題や運営をしてくださった方々には感謝ばかりです。是非来年も参加したいです。