ISUCON10本選に並行チームとして参加しました

公開:2020/10/04
更新:2020/10/04
3 min読了の目安(約3500字IDEAアイデア記事

ISUCON10予選は敗退しましたが、運営経験者ということもあり縁があって『本選問題を解いてみよう!チャレンジ企画』という企画にて並行チームとして本選に参加できることになりました。

去年の本選の後に、今年の運営の白金動物園のメンバーから自分が作ったISUCON9予選のベンチマーカーを始め、ISUCON9予選をとても褒めてもらえていました。そんなISUCON9予選のベンチマーカーを理解した上で作成した問題は是非解きたいと思っていました。なので連絡をもらってとてもうれしかったです。

チームは予選とは違うメンバーと出るか、1人で出るか迷ったのですが、予選の時にインフラに気を取られてアプリケーションに手が回らなかったという反省からインフラを任せられるメンバーを入れたかったので https://twitter.com/d_cyrill1129 さんと2人で参加しました。ISUCON7の時に鍋部というチームで出た時は3人チームだったので、今回は2人前ということで「鍋部(2人前)」というチーム名にしました。

実際に使用したリポジトリは以下です。例によって時間は目安で正確なものではないのと、自分の作業範囲を中心に書いています。

https://github.com/catatsuy/isucon10f

作業

~11:00

いつも最初にやっている作業をやっていました。とりあえず3台のインスタンスのスペックがバラバラで活用方法が難しい印象でした。1のインスタンスのメモリが少なすぎてgitリポジトリすらpushできなかったので2のインスタンスで作業行うなど初手から翻弄されます。

とりあえず手元でGoのコードをコンパイルして動かすことに成功していましたが、3つあるプログラムがそれぞれなんなのか分かっていませんでした。

またnginxではなくenvoyだったのでアクセスログ解析が普段通り行えず、まずどこから見ればいいのか分かりません。またドキュメントの確認をまだ十分に行ってなかったのでアプリケーションの仕様が詳細に書かれていることにまだ気づいていませんでした。

~12:00

コード量が多く、解析もうまくできていません。envoyからnginxに置き換えをしようとしていましたが、うまく動かなかったのでenvoyでアクセスログをjsonで取得できるようにしてなんとかアクセスログの解析結果が取れるようになったのこの時間帯です。

またこの辺りからコードの全体像の把握は諦めてとりあえずできそうなところから手を動かす方向に舵を切りました。

~13:00

/api/contestant/dashboardのキャッシュを1s行えるとあったので、そこに着手しました。1sは短いのでキャッシュがない状態で複数リクエストが来るのでzero time cacheを使いたかったのですが、実装時間を考えてexpiredする単純なキャッシュをアプリケーション側に追加しました。

今から考えると、初手にこの作戦を取ったのが主な敗因でした。解析が十分行えていない状態で突き進むのはよくないのですが、この時間まで何もできていないことに焦っていました。

~14:00

Web Pushを実装することでアプリケーションの挙動が変わることがマニュアルにあり、TODOコメントを見つけました。これによって /api/contestant/notifications の処理をほぼ削除できるのでスロークエリから消せそうだったので着手しました。

envoyだとファイルの配信など基本的な機能が色々ない記憶があったので、304を返したりとかするならnginxにしたいところです。これくらいの時間帯にnginxの置き換えに成功します。

~15:00

Web Pushがサンプルアプリケーションからコピペしてコンパイルが通るように書き換えていったらとりあえず動きましたが、スコアが1000点くらいに下がってしまいました。
Web Pushを遊行することによってベンチマーカーの性質が大きく変わってしまいます。これによって/api/contestant/notificationsの最適化が不要になるので、最終的にどちらがメリットがあるのか判断できませんでした。ここでスコアは大きく下がってしまうがWeb Pushを有効にしたまま突き進むことにします。この判断も今から考えるとよくない判断だった気がします。

またGoのアプリケーションが無駄なlogを吐き続けているので無効にしました。

~16:00

スコアが下がっていましたが、TeamCapacityを増やすことでスコアが元に戻せないか検証していきました。そこである程度までは戻せますが、MySQLが少しでも詰まるとキャッシュ周りの挙動が怪しくなりベンチマーカーが一気に失敗するようになりました。レスポンスの整合性チェックは厳しくするとタイミングの問題で正常系もエラーになってしまうので、真面目に厳しくするのは難しいのですが、今回のベンチマーカーは真面目に実装されていて誤判定をすることはありませんでした。

少しでもMySQLの負荷を減らすためにnginxのキャッシュを使って/api/contestant/dashboardへのリクエストを減らしてみましたが、状況は大きく変わらなかった気がします。

MySQLの負荷を減らすためにconstantをキャッシュしようとします。

ラスト

キャッシュがうまく動かず、ベンチマーカーがかなり真面目に整合性チェックを行っていそうでした。残り時間が少なくなっていて、もう大きく書き換える時間が残ってない状況でした。最終的にスコアは11129でした。

感想

問題が非常に多く、8時間で解く問題ではないと思いました。Web Pushを有効にした方が後々有利なのかどうかの判断も難しく、うまく戦いきれなかったのが心残りです。情報が公開されてからになると思いますが、個人で解いてしっかり復習したいと思います。

あとポータルと問題のデザインが似ているので、今どっちを触っているか分からなくなることが多かったです。faviconが特徴的だったので途中からfaviconだけで区別をしていました。

ベンチマーカーは整合性チェックが歴代でもおそらくトップレベルの厳しさだったと思いますが、誤判定らしきエラーは見ませんでした。ベンチマーカーも安定していて困ることはなく、非常に快適でした。

また本選問題と同時に公開された https://github.com/isucon/isucandar がとても気になっています。

ISUCON9予選ベンチマーカーに思想は似ていそうですが、ISUCON9予選ベンチマーカーは実装が複雑になったり、変更が難しくなることを嫌ってライブラリを使わずに全シナリオで並行プログラミングを意識した記述にしました。
この構成は実装のシンプルさに繋がっていましたが、並行プログラミングに詳しくない人には非常に難解なプログラムのようで、かなり勘違いされていることが多いようです。ちなみに書いた本人としてはコード内のコメントや各種ドキュメントも充実させたのと、ISUCONベンチマーカーに求められた仕様に対して、できる限りシンプルな実装を目指しただけで、難解なプログラムを書いたつもりは実はないです。ISUCONのベンチマーカーに求められている仕様がそれだけ複雑なのでやむを得ないと思っています。

自分としてはISUCON9予選ベンチマーカーでISUCONのベンチマーカーに対しては答えを出したと思っているのですが、isucandarは違う問題意識の元で作られているようです。まだコードを読み切ってないので、これについては読んでから別の記事で感想を書きたいと思います。

運営の方々、本当にありがとうございました。ISUCONが最高のイベントで自分が大好きなイベントであるということを再確認しました。今から精進していきます。来年もあるなら絶対に参加しますし、ISUCON9予選について聞きたいことがあれば色々話せると思うので、来年の運営の人からの質問も(ネタバレにならない範囲になるから難しいと思いますが)答えます。よろしくお願いします。