2024.01.10 追記
予定していた連載(?)が終わったので、元記事であるここにインデックスを作成しておくことにします。②以降の記事は以下のリンクから飛ぶことができます。
- ISUCON14延長戦の記録② インデックスの追加 - なまえは まだ ない
- ISUCON14延長戦の記録③ N+1どころじゃない問題の改善 - なまえは まだ ない
- ISUCON14延長戦の記録④ 激重の集計クエリを軽量化する - なまえは まだ ない
- ISUCON14延長戦の記録⑤ マッチングアルゴリズムを改善する - なまえは まだ ない
- ISUCON14延長戦の記録⑥ MySQLサーバーを別インスタンスにする - なまえは まだ ない
- ISUCON14延長戦の記録⑦ インメモリキャッシュに手を出す - なまえは まだ ない
- ISUCON14延長戦の記録⑧ インメモリキャッシュに手を出す(その2) - なまえは まだ ない
- ISUCON14延長戦の記録⑨ N+1問題の解消とクロージング - なまえは まだ ない
ISUCON14について
先日の記事で報告したとおり、12月に開催されたISUCON14に出場しました。 大変好評だったのか、本戦を終えた後も感想戦モードと称して再挑戦ができるようになっています。環境維持もタダではないでしょうに、運営の皆さまには感謝しかありません!
先日の結果がとても悔しかったので、また一から問題を解いてみてどこまで点を伸ばせるか挑戦してみました。延長戦だ!目指すは本戦の優勝スコアである58,153点!
延長戦のルール
- 環境やルールは基本的にISUCON本戦のレギュレーションに準拠
- ただし解説と講評は読んでOK
とりあえず当時の状況を再現しつつ進めてみます。が、私個人の技量・発想には限界があるので、作問者の解説を読んでヒントを得ていこうと思います。
なお、実際に改善したアプリケーションコードは以下のリポジトリで公開しています。
競技用の環境を整える
monitorサーバーのセットアップ
先日の記事でも書いたように、競技環境のモニタリングにpproteinを導入しました。これが大変便利だったので、簡単にセットアップするためのリポジトリを作りました。
今後の競技でも利用できるよう、テンプレートリポジトリ設定してあります。
この環境とISUOCNの競技環境をそれぞれデプロイし、monitorサーバーをセットアップしておきます。 その後、monitorサーバーから競技用サーバーに対してSSHポートフォワーディングを確立します。pproteinは双方向にHTTP通信をするので、双方向でトンネルできるよう次のように実行します。
ssh -L 19001:localhost:19000 -R 18080:localhost:80 isucon1
isucon1 はその名前まんまですが競技用サーバーの1台目のエイリアスです。次のような設定をmonitorサーバーの ~/.ssh/cofig に記述しておきます。
host isucon1
HostName <競技用サーバーのグローバルIPアドレス>
User isucon
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 60
競技用サーバーはpproteinエージェントを19000ポートで起動します。
これをmonitorサーバーの19001ポートとリンクさせ、pproteinサーバーには localhost:19001 で各種ログを収集するように設定します。
また、pproteinサーバーには収集を開始するためのWebhookが存在します。 そのWebhookを競技用サーバーからリクエストするために、競技用サーバーの18080ポートをmonitorサーバーの80ポートにリンクしておきます。
複数台に展開したときはtmuxで複数セッションを作成して次のように設定します。ホスト毎にローカルポートが被らないようにだけ注意が必要です。 ただし、今回は結果的に3台目は使わずに終わってしまいました。
ssh -L 19002:localhost:19000 -R 18080:localhost:80 isucon2 ssh -L 19003:localhost:19000 -R 18080:localhost:80 isucon3
競技用サーバーのセットアップ
競技用サーバーにはpproteinエージェントでログ収集するため、Nginxアクセスログのフォーマット、MySQLのスロークエリログ設定を入れておきます。先に紹介したレシピに競技用サーバー用のレシピも用意してあるので、それを実行すればOKです。
git clone git@github.com:furusax0621/template-isucon-recipe.git ~/recipe
cd ./recipe
./install-app.sh
アプリケーションコードへの仕込み
pproteinでログ収集するため、アプリケーションコードに仕込みをしていきます。 完全な差分は以下のPull Requestを参照してください。
やることは2つです。
まず、pproteinエージェントをアプリケーションコード内で稼働させます。アプリケーションのサーバーが稼働するタイミングで次のコードを入れます。ゴルーチンで実行する必要があるので、その点に注意しましょう。
go standalone.Integrate(":19000")
先に述べたとおり、この19000ポートに対してmonitorサーバーからリクエストが飛んできます。
また、先述のWebhookにリクエストするコードを仕込みます。 Initializeエンドポイントの最後に入れておくことで、ベンチマーカーが動くのを契機にpproteinによる収集を開始できます。
if _, err := http.Get("http://localhost:18080/api/group/collect"); err != nil { writeError(w, http.StatusInternalServerError, err) return }
まとめ・次回予告
というわけで競技を始めるための環境が整いました。 この状態でベンチマーカーを回して情報を収集し、そこからようやくチューニングの旅が始まります。つづく。