s平面の左側

左側なので安定してます(制御工学の話は出てきません)

ISUCON 8 予選に参加した & 敗退した

関連エントリ

今回、一緒に参加したチーム「Oysters1」メンバーのブログエントリーはこちら。

blog.zoe.tools

↑戦略・戦術などはこちらで詳しく解説している。

blog.pinkumohikan.com

ちなみに とどけRevert "とどけ" したのは私だ。

ISUCON 8 予選中の風景
作業中の風景(実は別撮り)

ISUCON とは

詳しい解説は公式 Blog に譲るが、ISUCON とは「Iikanjini Speed Up (=いい感じにスピードアップ) Contest」の略。

与えられた web アプリケーションを(レギュレーションの範囲内で)とにかく速くしたもの勝ち、というコンテストである。

isucon.net

実は昨年も予選に参加しており、今回は 2 回目の参加だった。

(今さら気づいたが、昨年予選に参加した際のブログ書いてなかったのか。。。)

自分の役割とやったこと

私は以下の 2 つを担当した。

  • ローカル開発環境の構築
  • アプリケーション側の改修

10:00~12:00 ローカル開発環境構築

予め Go のアプリケーションをビルド・実行できるような設定を Docker / Docker Compose で準備しておいた(チームメンバーが準備してくれていた)ので、それをベースに

といったことを行って、開発環境を準備。

ここまでで 2 時間と想定より時間がかかってしまったので、本来の分担であったプロビジョニングや設定ファイルのバックアップなどは別メンバーに巻き取ってもらった。感謝。

12:00~15:30 getEvents() 関数の N+1 問題を解消

環境ができあがったので、アプリケーション機能をブラウザから実際に確認しつつ、pprof や kataribe などを使って改修箇所にあたりをつけていく。

ちなみに今回の題材はイベントの座席予約アプリケーション。

まず取り掛かったのが、イベント情報一覧を取得する getEvents() *1という関数。

この関数は中身でイベント詳細情報を取得する getEvent()*2をループで呼び出す、いわゆる N+1 問題を抱えていたのでそれを修正。

これをやってトップページの速度は劇的に改善されたのだが、スコア的には 1,000点 → 2,600 点くらい。

今になって思えばこちらは後回しにして getEvent を先に改修したほうが良かったような気がする。

プロファイリングツールを活用しきれていない感。

15:30~17:00 getEvent() 関数の N+1 問題を解消

引き続きプロファイリングツールを回して、今度は先述の getEvents() の中で呼ばれていた getEvent() を対象に定める。

こちらも中身で座席の予約状況を取る処理が N+1 になっていたので同じように修正。

こちらの施策はしっかり刺さって、スコアが一気に 20,000 点くらいまで上がった。

ここで一時的に(最高スコアではなく、最新スコアでだが)暫定 5 位になったりして、みんなで歓声を上げていた。

17:00~18:00 バグ修正/ひたすらベンチマークを回す

この時点で、インフラ側の施策も合わせて 25,000 点あたりをマークするが、ベンチマークがたびたび fail するようになる。

ここからの残り時間は「原因究明」→「ソースコード修正」 →「ベンチマークを回して確認」を繰り返す*3

厄介なことに fail は 100% 再現しなかったので「コードを修正しては、数回実行」を繰り返すことになり、大幅に時間を取られてしまった。

結局最後の最後まで、きちんとベンチマークが回るかどうか不安な状態でタイムアップを迎えた。

ちなみに とどけRevert "とどけ" のコミットはこのときの産物。

競技終了後、Discord の感想部屋でのやり取りを見るに、どうやら同様の状態に陥ったチームは他にもあるようで、出題者が意図的に仕掛けた問題だったのかもしれない。

結果・振り返り

結果は、再起動試験が通らずに失格*4

isucon.net

fail 23,034 Oysters1 (3)

以下、感想も含めた振り返り。

念願の Go 実装での挑戦

昨年の予選に参加した後から、「来年は Go 使いたいねー」という話を仲間とし続けていたので Go 実装での挑戦を選んだ。

私はアプリケーション担当だったが、普段業務で Go を書いているわけではない。

それでも以前にプライベート開発で Go に触っていたこと、直前に Tour of Go を一通り復習していたことで、当日は大きな問題なく改修に取り掛かれたので良かった。

いざ Go 実装で挑戦してみて

  • ビルドを通す必要があるのでうっかりミスを未然に防げる
  • 定義されている構造体を見るだけで概ねデータ構造を把握できる
  • DB のデータを変数に代入する機構がシンプル

といった点から感触が良く、アプリケーションのロジック以外に割く頭のリソースが少なくて済んだような気がした。

出題傾向

今回の予選問題は画像の配信がなく、久々に「最初のボトルネックがアプリケーション側の N+1 問題」というものだった。

近年は「N+1 問題を解消してもさほどパフォーマンスが向上しない」というパターンが多かったので、アプリケーションを担当していた私は面目躍如にテンションが上がっていた。

もちろん、さらなるハイスコアを目指すためには複数台構成を上手く活用しなければならなかったので「アプリケーションさえ改善できればよい」というものでは無かったが。

pprof などプロファイリングをきちんとできた

昨年はソースコードベンチマーク結果だけを見て雰囲気で施策を決めていた。

今回は pprof, kataribe などのプロファイリングツールを使い根拠を持って施策を決められたので、チームとして成長を感じられた。

ただし準備や事前調査はチームメンバー任せだったのと、いまいち使い切れていない感もあるので、ここは継続して習得していく所存。

各作業を練習して精度・スピードを上げていきたい

環境構築に 2 時間かかっているのでそのスピードや、アプリケーションの改修スピードが上がれば次の施策を打つ時間も取れただろう。

ここは練習あるのみか。

おわりに

(ここだけ「ですます」調で)

一緒に参加したチームメンバー、当日の他の参加者のみなさん、そして何よりこの年に1回のお祭りである ISUCON の準備・運営に携わったすべてのみなさま、お疲れ様でした & ありがとうございました!

10/20(土)の本戦の様子も楽しみにしています!

*1:ややこしいが、こちらは複数形

*2:こちらは単数形

*3:もちろん「再起動して正しく動くかの確認」も忘れず

*4:仮に試験が通っていたら 40 位