ISUCON5に参加しました

ISUCON5にチーム名"ピザはバランスいい"で参加して、予選突破しました。
メンバーはtakashabeさんとnohamaさんと私の3人です。

全体的な方針については、 過去問とボーダーの点数ややったことを見る限り、 初期構成を改善しコードの大きな書き換えはしなくても予選を突破できる点数に到達できる、 という確信があったので nginx+ruby+MySQL の構成で実装しました。

役割はこんな感じで分担しました

takashabeさんにnginxとMySQLの設定を行って頂きました
ISUCON 5予選を突破してきました - takashabeのブログ

アプリケーション改善班では、最初はペアプロみたいにやっていたのですが、 14時を過ぎた頃には作業的な部分が残り出したので分担して書き換えていました。

今回やって大きくスコアが上がったもの

  1. unicornのworker数を増やした(初期設定は1だった)
  2. is_friend?が何度も呼ばれているのを改善
  3. '/'で1000件取ってループしてるのをクエリ一つで済むように改善
  4. relationsへのSELECTクエリの改善
  5. footprintsへインデックス追加
  6. viewからget_user(user_id)されているのを改善
  7. commentsにインデックスの追加

やりたかったけどできなかったこと

  • entries, commentsテーブルのカラム追加(時間がかかりすぎたので断念)
  • viewでDBに接続されてる部分の削除(気づいたのが遅すぎ(1740頃)で手をつけなかった)

上記のような感じでした。 それぞれもう少し詳細に書きます。

2 is_friend?が何度も呼ばれているのを改善
コードを眺めていて、最初に目についた部分です。 is_friend?の中で1回クエリが実行されるので、そのユーザのフレンドリストを全部取得した。 クエリの数が大きく減ったはず。

3 '/'で1000件取ってループしてるのをクエリ一つで済むように改善
2の続きで、1000件取ってループしなくても、'where in' でフレンドのID突っ込めばクエリ一回で済むよね、ってことでクエリを改善した。

4 relationsへのSELECTクエリの改善
relationsへのSELECT文でORを使っていたのですが、INSERT文を見てみると双方向にレコードが作成されていたのでORを削除(レコードを半分にするか迷ったけど、データが壊れないようにSELECTを変更)

5 footprintsへインデックス追加
footprintsテーブルにインデックスがなかったので、user_idをインデックスに追加

この辺で、作業を分担し始めた。 ここまで行った後のクエリログを見ると、 entries,commentsをJOINしたものとusersへのSELECTが大きなボトルネックになっていた。

6 viewからget_user(user_id)されているのを改善
MySQLのクエリログを見るとusersへの単純なSELECT文が何度も行われているが、app.rbを見ていても原因がさっぱりわからなかった。viewを見てみるとget_user(user_id)されてる部分が何箇所も見つかった。usersテーブルとJOINするようにクエリを変更しusersへのクエリが激減した。

7 commentsにインデックスの追加
entry,commentsをJOINするSELECTが遅いということで、いろいろ試した結果 ORDER BY が遅いらしいという推測し改善することに。インデックスを見てみるとWHEREで指定されてるものと、created_atにはインデックスがあるのになぜか遅い。私自身は知らなかったのですが、一つのSELECT文でインデックスは一つしか適用できない、とのことでcreated_atのインデックスがORDER BYに使用されていなかったらしい。インデックスを追加したらかなり早くなった。

この辺までやって17:20頃。この後は再起動したり、それぞれ簡単に改善できそうな部分を探したりしてた。

ここから個人的な感想とか学んだこと

最初に、ISUCON初参加でしたが予選突破できてとても嬉しいです。 社内のメンバーで2~3ヶ月前くらいにISUCONに出ようって話が出て、週に4~6時間ペースで練習してきたかいがありました。 月・木の業務終了後に2~3時間くらい、過去問やった後に、ピザを食べに行く(チーム名に反映されています)ということをやっていました。 いろんな人の記事を見ながら過去問でいろいろ試したこと、kazeburoさんのyapcでの”ISUCONでの勝ち方"の2つがとても大きかったと思います。 予選当日は緊張と焦りでtypoしまくる私に対して、nohamaさんが冷静に改善を続け、takashabeさんはベンチを走らせた後に解析結果を出してくれたりと、チームメンバーにはとても感謝しています。

今回、やって学んだのはやったことの7で書いたとおりMySQLのインデックスに関することでした。 予選当日以外では学ぶことだらけでした、いろんなツールに触れたりできたので良い経験になりました。 反省点としては、コーディング能力が大きく落ちていると感じました。 5年以上前ですが、競プロやってた頃はもっと早く正確にコーディングできていたなーと思ったので、 AtCoderなどで練習しようかなと考えています。

本戦では、他のチームすごい人ばかりで優勝できる気がしませんが、 少しでも良い結果を残せるように、1ヶ月間準備していきたいと思います。

おまけ
ゆるゆり3期放送開始楽しみ