はじめに
「がんもどき」(@sappi_red, @ryoha, @temma)でISUCON10の本選に参加して、全体3位・学生3位をとりました。
スコアは34767点でした。
構成
使用言語: Go
- 1台目: アプリケーション(仮想ベンチマークサーバー)
- CPUコア数: 2, メモリ: 1GB
- 2台目: DB(MySQL 8)
- CPUコア数: 2, メモリ: 2GB
- 3台目: Envoy + アプリケーション(仮想ポータル)
- CPUコア数: 4, メモリ: 1GB
やったこと
当日まで
一週間前くらいは技育展の発表の準備をしていて練習したりする時間が取れなかったのですが、前々日と前日には軽くISUCON9の決勝を触りました。
10:00
予選と同じく全員リモートで参加しました。
開始後は@temmaがsshのconfigを書いたりMakefileの調整やツール系のインストールやgitの導入などをしている間に、@sappi_redと@ryohaでマニュアルを読みました。
マニュアルのうち、Webpush関連の部分が長かったので早めにタスク切り分けるためにWebpushは@ryohaに任せて、@sappi_redはそれ以外の箇所のコードを読むことにしました。
Goに切り替えたあとの初回のベンチを10:31に回して6362点でした。
11:00
htop
を見ていてMySQLのCPU利用率が高かったのでとりあえずMySQLを2台目に移すことを@temmaに頼みました。移す手間がそこまでないのと最終的には移すことになるだろうという読みが理由です。
その間に@ryohaはwebpushの実装を進めて、@sappi_redはpprof/fgprofの測定しました。
/audeience/dashboard
の負荷が支配的だったのでそのあたりを改善するために@sappi_redが下のような変更を入れました。
/audience/dashboard
でCache-Control: max-age=1, public
とExpires: 返答の1秒後
のヘッダーを付与 (スコア変化なし)- チームの学生判定をカラムで保管するように (バグらせてあきらめた)
12:00
12:10に@temmaがMySQLを2台目に分離して、そのままslowqueryの設定とDBのチューニングをしました。
@sappi_redは/audience/dashboard
の返答をアプリ側で0.9秒キャッシュするようにしました。
この二つのあとのベンチで11852点が出ました。
その後、@temmaがindexをいくつか張りました。
最終的にはアプリ側も分離するだろうということで仮想ポータルを3台目、仮想ベンチマークサーバーを1台目に残すことを@temmaに頼みました。ここでカーネルパラメータの設定などもしました。
13:00
@sappi_redが/audience/dashboard
と/contestant/dashboard
でsingleflightを利用するようにすることで同じクエリでDBを同時に叩いているのを取り除きました。
このときのスコアが13719点でした。
さらに@sappi_redがsingleflightがより効率よく効くように書き換えました。これは「コンテスト中かつリーダーボードが凍結中」でないときは/audience/dashboard
と/contestant/dashboard
は共に同じ結果を返していることに注目して、singleflightの同じグループになるような変更をしました。
このときのスコアは14162点になりました。
pprofを見るとリーダーボードの構造体をprotobufに変換する箇所でCPU時間を消費していたので、構造体ではなくprotobufの[]byte
をキャッシュするようにしました。
これでスコアが16718点まで上がりました。
14:00
このあたりで何でかmasterのコードでベンチが通らなくなって格闘しました。
結局何だったのか今もわかってません。
原因の一つとしてわかっているのはトランザクションを取った後、コミットするのを忘れている箇所があって、その結果MySQLがそれを解放できずに上限にひっかかり落ちてたことです。
15:00
@sappi_redがloginRequired
内でgetCurrentContestant
を呼ばないように関数の呼び出し順を入れ替えたりしました。スコアの変化はなかったです。
16:00
ここでようやくチーム数上限の存在を思い出して、10だったのを50に変更しました。
これで一気にスコアが29822点まで上がりました。
contestantがread heavyだったので@temmaがメモリに載せるのをはじめました。
clarificationsも多少重かったので@sappi_redが/admin/clarifications
と/contestant/clarifications
のN+1を解消しました。
ここでスコアが30123点になりました。
もうちょっとチーム数上げたら点数伸びるかなと思って、50から70に変えましたが、30666点でそんなに変わりませんでした。
17:00
@sappi_redが/registration/team
でLastInsertIdをとるのにクエリを叩いていたのをINSERT INTO
での結果を利用するように変えて、31818点がでました。
17:20にcontestantをメモリに載せるのが実装し終えたのですが、DBでdeadlockが発生するようになってしまい、導入するのを泣く泣く断念しました。
17:30になったのでコードフリーズをしてログを取り除いて再起動試験をしました。
ログを取り除いてチーム数上限を調整して、最終的に自分たちで実行したのは34180点でした。
おわりに
@sappi_red: 練習自体は何回か行ったのですが、初参加だったので本番は初めてでちょっと緊張してました。今年はリモートだったので例年よりは幾分かそれが和らいだのもあったかなと思ってます。
とても楽しかったので来年も参加したいです!
@temma: めっちゃ楽しかったです。3人で練習もちょこちょこやるのも楽しかったし、それを通しての発見も多かったですね。来年は優勝suruzo!!
@ryoha: traPのなかよし部(ユニちゃんズ)であるこの三人でわちゃわちゃできて楽しかった~~~~~。来年はすべてをなぎ倒せるようになりたい。現地に行くのはノートパソコン半強制みたいになって辛いのでリモートで助かった。