ISUCON8予選は学生枠6位で本戦出場が決まりました
ISUCON8の予選に、メルカリで一緒だった@zaq1tomoと@inatonixとzin-gonic
というチーム名で出場しました。
結果は学生枠6位だったので、やったこととかまとめます。
事前準備
- 二度のisucon合宿を行った(どちらも環境構築で頓挫)
- 何回か集まってisucon7の過去問練習
- ishoconという株式会社scoutyさん主催のコンテストで練習した
- hidakkathonという株式会社会社サイバーエージェントさん主催のコンテストで練習した
- 前日に当日と同じ要領でhidakkathonの問題をみんなでやった
とまあ初出場ということもあり結構ちゃんと準備して、何も言い訳できない状況だったのでとりあえず通過できてよかったです
やったこと
チューニング対象は、イベントの座席予約アプリでした。
言語は、3人の技術スタック的にGo一択でした。
@nakabonne: インフラ担当
@zaq1tomo: アプリ担当
@inatonix: アプリ担当
序盤
@nakabonne
- ssh公開鍵登録
- dotfileをclone
- ベンチ走らせてhtopでリソース確認
- リスタートスクリプトの準備
- スロークエリログを仕込む
- 再起動に備え、自動起動設定をする
- プロファイルングツールalpを仕込む
- ログローテートスクリプトを仕込む
- alpに渡すためにh2oのアクセスログをLTSV形式にする
リバースプロキシは完全にnginxのつもりでいたので、h2oアクセスログをalpがパースできる形式で出力するのに結構時間かかってしまって、大迷惑かけてしまいました。
本戦では爆速でやりたいです。
ちなみに今回はnginxに差し替えてる方が結構いたので、インフラ担当としてその辺のトレードオフも見積もれるようになりたいです。
@inatonix, @zaq1tomo
- マニュアル読む
- ひたすらコード読む
- pprofを仕込んでボトルネック探す
- スロークエリログ見ながらボトルネック探す
方針決め
リソース
弱者の戦い方として、無理に複数台構成はしないと最初から決めていたため、ゴリゴリインメモリキャッシュを使おうと話していました。
実行時にCPU使用率が100%に張り付くので、なるべくredis等の別プロセスは立ち上げたくないと感じたので、キャッシュするならGoプロセス管轄内のメモリに乗せようとなりました。
ただ、mariadbが大分CPU食っているのでdbだけ別インスタンスに移したい気持ちはありました。
スロークエリ
reservationsテーブルから全座席ごとにselectしてるクエリが37万回呼ばれていて、これを解消しない限り次に進まないことがすぐに分かりました。
今回はボトルネックが明白だったため、学生でも迷わずに進める良問でした。
アクセスログ
一番上の /api/users/:id
で、先程の重いクエリが流れていたため、平均9秒かかっていました。その他レスポンスタイム上位のエンドポイントはほとんど同じクエリがボトルになっていました。
中盤
@nakabonne
- 二人の修正が競合しないようにひたすらデプロイ
reservation
テーブルのuser_id
とかにindex張ってみる → 意味なし- h2oでロードバランシングしてみる → 出来なかった
reservations
テーブルにはevent_id
とcanceled_at IS NULL
にマルチカラムインデックス張るのが正解だったっぽいです。
単体テーブルへのクエリならまだいいのですが、内部結合となると実行計画が全く理解できず死亡しました。
@inatonix, @zaq1tomo
- それぞれ別のアプローチでgetEventsクエリのN+1解消に取り組む
- @inatonix: Goプロセス内インメモリキャッシュ
- @zaq1tomo: クエリ変えてクエリ数減らす
僕のアクセスログ解析が遅れたせいもあり、全くスコアが上がらず完全にお通夜モードになっていた15時頃(だったかな)に、@zaq1timoのN+1修正が火を吹き1000点→10000点と10倍になりました。
/api/users/:id
の平均レスポンスタイムも9秒→1秒まで解消していました。
終盤
@zaq1tomoが合計料金をSUMするクエリをチューニングしてくれてちょっとスコアが上がり、諸々のログを吐かないようにしたら13000点を超えるようになりました。
ただ、ランダムにfailしたりしてハラハラしていました。
競技30分前に再起動し最終的に14000点を超えたところでコードフリーズし、お片付けを始めました。
感想
1392名参加している大会で、障害等を何も起こさなかった運営の方々がかっこよすぎました。
今回は各チームごとにベンチマークを用意してくれた(構成的にするしかなかった)Conohaさんにも感謝の念が溢れます。
本戦勝つぞー