ISUCON10に参加しました

今年二度目となるISUCON参加でした。 学生チームとして参加させていただき、メンバーは二人ながらも最後まで走り抜けたかと思います。 今年もGoで参加させていただきました。

本番まで行ったこと

  • 解析ツール選定
  • 過去問を解く
  • 使用しうるライブラリを簡単に導入できる

本番までにやったことはこんな感じだったかなと思います。

解析ツール選定

私のチームは以下を使用しました。

  • alp
  • mysqlスロークエリ

この2つに関しては、去年も同様に使用しており今年もお世話になることにしました。 また今年のISUCON10参加者には、NewRelicの特別ライセンスが配られており、こちらも検討し過去問を解く際に使用したのですが、 当日の導入コストや、このツールを使いこなせるまでになる時間があまりなかったので、今回は不採用とさせていただいきました。

使用しうるライブラリを簡単に導入できる

ISUCON当日は稼働時間が8時間しかなく、かなり時間的にシビアだと考えています。 そのため、一つのライブラリの導入も速やかに、導入し使用可能なように設定することが大事だと考えています。 過去問を解く際に色々あったほうがよい、使用したいライブラリをあげていきその導入を速やかに済ませるためのものを準備しておきました。

当日の流れ

12:00~13:00 開始?

ポータルにアクセスし、サーバリストが表示されるまで待ち。 レギュレーションを呼んでUserAgentをNginxで拒否する設定をローカルで作成・検証

13:00~14:00 セットアップ

インフラ側

  • git管理
  • alp導入
  • スロークエリ吐き出し
  • デプロイスクリプト
  • bashのセットアップ
  • DBのレコード数抽出

アプリ側

  • ファイル分け
  • logger, immcacheの導入
  • 全体的に遅い箇所探し(N+1等)

14:00~15:00 全体的に

セットアップが終わり、この頃からベンチが回せ始めたので、ベンチの結果をもとにalpで解析結果を見て遅い箇所の変更を検討し始めました。 searchが遅いことはわかっていたので、一旦INDEXを貼るくらいの変更をしました。 そこまで遅くはなかったのですが、なぞって検索のN+1を解消する方法を検討もこの辺りから少し考えていました。

15:00~17:00 INSERT部分の修正

searchの修正方法がぱっとせず、chair, estateのINSERT処理が複数回(500回?)呼ばれていたのでこれを一回のINSERTで済ませるように変更しました。 16時ぐらいにsearch系は範囲検索しているが固定値で絞り込みできることにもう一人のメンバーが気づき、解消に取りかかってもらいました。

17:00~18:00 なぞって検索

nazotte検索はN+1を解消するために内外判定をGoでやる方向で進めることを考えていました。しかし内外判定をいい感じにやることができず、、、 そこでMySQL側で解消する方法を考えていた所どうやらMySQLにはGEOMETRYなるタイプが存在していることを知りました。 また、このGEOMETRYタイプのレコードにはどうやらSPATIAL INDEXなるものを貼ってインデックスを用いて内外判定が出来ることを知りました。 なぞって検索は、繰り返しの中のクエリ(内外判定)を外に出し、内外判定をPOINTではなく新たに追加したGEOMETRYタイプのカラムに対して行うことでかなりの高速化ができました。

18:00~20:00 物件検索修正、initializeの処理、ISNERTの非同期化

chairの検索機能のクエリ部分の範囲検索を等価検索に変更する箇所はもう一人のメンバにやったもらっていて、estateも同じように出来るという話だったので、estateの検索機能の修正に入りました。 fixturesのなかにある条件によって検索範囲をIDでもちその範囲でリクエストが来たらIDに変換し、検索を行うという修正をしていました。

initializeで呼ばれる処理をかなり愚直に書いており、そのままだと30秒以内に終わらない可能性が大いに出てきました。 スキーマの変更等でかなり時間を取られ20秒以上かかっていました。 そのため、DBの初期状態をdumpしinitializeではそのダンプした結果を挿入することでinitializeのタイムアウトを防ぎました。

また、chairの検索機能を任せていたメンバーの変更がなかなか終わらずここでバトンタッチし、最後の修正を終え ブランチを整理して、最後の1時間のベンチに備えました。

この時点で処理は高速化できていたと思うんですが、そうするとINSERTの箇所で499番が連発しベンチがfailするようになりました。 これは、ベンチが通るか賭けだったんですが、トランザクションをなくすことと、INSERT部分をgoroutineを生成して非同期で行い、レスポンスはすぐに返すように修正しました。 これで無事ベンチは通るようになりました。

20:00~21:00 initializeの処理のバグ追求

ここまで結構なチューニングを行ったかと思うんですが、最後の最後で点数が伸びていない状況でした。(800点ぐらい) その原因を探っていると、dumpしたものをinitializeで挿入しているのですが、dumpしたものとは違うスキーマのテーブルを持ったDBが作成されてしまう現象が起きていました。 dumpしたものは正しいことは確認済みで、この原因追求をしている間に時間制限が来てしまい、最終スコア800点ぐらいで無事予選敗退でした。

終わりに

今年のISUCONは、かなり本戦出場が濃厚だったと思ってるんですが、終わってみるとよくわからない挙動への対処が間に合わず 無事予選敗退してしまいました。正直かなり悔しく、そのまま一人で地元のダイニングバーに行きやけ酒をしました。 今年の敗因をしっかり振り返り、出来ることを少しずつ増やし来年は本選出場できたらなと思ってます。

最後にはなりますが、今年の運営はsshキー問題・ポータル落ち・インフラ間に合わないなど、かなりトラブルがあったようにおもいました。 そんなトラブルがありながらも日にちにの延期をせず素早い対応をしてくれたこと、参加側として最後まで走り続けられたことにとても感謝しています。

お疲れ様でした。