学生枠で出場した去年に引き続き、今年は新卒社員になった@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もメモリも使いきらない状態のまま提出となった。
この辺の経験不足が敗因なのかなあと思っているのと、正直このラインまでやれば予選抜けられると思っていたので、レベルが上がってるような気もした。
感想
めちゃくちゃ楽しかったし、ずっと集中しててすごい疲れた。去年は学生枠でギリギリ本戦に出してもらった感じだったけど、今年は去年よりちゃんとチームで連携してスコアが上げられて、メンバーの成長が感じられてよかった。
今年結構テンプレートエンジン周りを触ってて、その辺練習の時は最適化とかやってて今回の問題でも直せるところあるなと思ったけど、本番ではそのレイヤーにボトルネックが移せなかったのが悔しかった。
次から次へと直すところが出てくる面白い問題で、出題や運営をしてくださった方々には感謝ばかりです。是非来年も参加したいです。