2022/07/23 (土) ISUCON に出た

同僚の誘いもあって ISUCON というプログラミングコンテストに参加することになりました。しかしコンテスト当日だというのに、寝不足で頭はぼんやりしているし、目がちかちかしています。何が原因というわけでもなくて、ただ眠れなかったから起きていました。そのうち3時を回って4時も過ぎて、体のほうがおかしくなってしまったみたいに思われます。予定していた電車にも乗れず、出だしから滑ってしまった感じです。

それでも、どうにか会社について、チームメンバーと合流しました。バージョン管理して、分析用のログをとるというのが定番の流れですが、いきなりつまづきます。mysql のスロークエリログファイルを touch で作ってしまったため、暗黙のパーミッションエラーでハマってしまい、足止めをくらいました。どうにかして復旧したスコアはだいたい1000点くらいでした。ストレスと緊張で膀胱が縮まり、尿漏れしそうな感覚を思い出しました。その感覚は障害対応と似ていました。一刻も早くバグを直さなくてはいけない、時間は迫り、手段を選んでいる場合ではない。そういう感覚です。喉の奥に押し込むようにチキン南蛮弁当を食べました。

ここからようやくチューニングです。データベースにインデックスを与えようとしたのですが、スキーマファイルにインデックスを設定しても反映されません。強引にスキーマファイルを適用してみたところ、必要な初期データが消滅して、環境がクラッシュしてしまいました。一人はリカバリし、ほかのメンバーは2台目のマシンでチューニングを行うことにしました。

チームメンバーの粘り強い調査のおかげでクラッシュした環境が復活しました。その間にバルクインサートを実装しました。having 句を使ってN+1クエリを解消しました。ランダムなユニーク値の計算を uuid ライブラリで計算するように置き換えました。不要なクエリを削ったりもしました。同僚の助けを得て Window 関数を使ったりもしました。じわじわとスコアが伸びるのをみて、私達は楽しくなってきました。各自が力を発揮できている気がしました。計測してわかったことをもとに、チューニングして結果を待つ。その繰り返しです。ベンチマークスコアが帰ってくるまでの数分間、高校生の頃に一人ずつテストを手渡される順番を待っているような感覚がありました。目論見があたっていると、楽しい気持ちになりました。ハイになって、普段言わないような独り言をペラペラ喋っていました。きっとアドレナリンが血液を巡っていたことでしょう。

さて、残り2時間ほどになったところでスコアは頭打ちになりました。mysql プロセスの CPU 消費量が減ってきたことを観察して、別の原因を探しました。ファイルロックに問題があるらしいことはなんとなくわかったのですが、どう改善すべきかわからず右往左往しました。その間他のメンバーは sqlite に問題があるようだと考えて、sqlite のデータベースにもインデックスを与えることにしました。しかしこれらは動的に生成されていて、どういう手順で適用すべきかよくわかりません。ログも取れるのは取れるのですが、私達には分析用のツールの知見がなく、指を加えて見ていることしかできません。私はもうこの時点で疲れ切っていて「疲れたな」と何度もぼやいていたと思います。体を突き動かしていた脳内麻薬は枯れて、ただ疲れだけが出てきたように思います。まともに考える気力もなく、チームメンバーの動きに任せていました。sqlite のインデックスがなんとなく当たっていそうだというところで、検証もせずに、私は足を止めてしまいました。

プロファイラの結果を見てなんとなく思ったのは、アプリケーションコードは比較的単純であるため、チューニングできそうなのはデータベースだけだろうということです。sqlite をやめて mysql にすればずっと作戦を立てやすいしそれ自体で性能が上がりそうだと予想はできますが、テストコードのない暗闇でそれをやるのはあまりに危険です。仕事で取り組んでも一週間くらいかかって、終わるかどうか怪しいくらいの難易度に見えました。少なくとも今からやるのは時間の無駄だというのは目に見えていました。

そうこうしているうちに時間が押し迫ってきたので、各種調査用のログを停止して4900点が出たところでギブアップしました。最後の一時間で nginx が奇妙なエラーを出していたのに気づいたのですが、ここも原因がさっぱりわからず太刀打ちできませんでした。

mysql と sqlite をここまでヘビーに併用するのはまともな製品ではまず考えられない設計だと思います。今回課題になったアプリケーションは、根底から技術選択が間違っているし、実践的ではないと思います。ただ、それは負け惜しみにすぎません。課せられた課題を解けなかったという事実がただ悔しいです。普段と違うフィールドでは、こうも力を発揮できないのだと、身の程を知らされました。

帰りの電車の中で、チューニングのアイデアがいくつか浮かびました。tenant でシャーディングするとか、sqlite から mysql に段階的に移行する方法などです。一度にやらずに一個のテーブルあるいは追加分のレコードだけを mysql に持っていくだけならできるかもしれません。ただの思いつきにすぎませんが、ただぼんやりしていた時間にできることが残っていたかもしれないと思うと、歯切れの悪さは残ります。もう一度チャレンジして、もっと良い結果を出して見せたいと心のなかでは思っています。けれどただ、寝不足の中で駆け抜けた8時間は少なからず身体にダメージを与えました。ただただ疲れた。横になりたい。そういう気持ちです。もう一度これをやるのかと思うと若さあるいは体力が足りない気もします。けれど次にこれを走りきったら心の勲章になるだろうという直感はあります。さてどうなるかわかりませんがとりあえず今は休みます。