ISUCON 9 予選惨敗記録
惨敗した。
当日のログもあまり残せておらず、記憶がすぐに劣化してしまいそうなので乱文になるかもしれないがここに記録しておく。
参加のきっかけ
社内の Slack で「興味ありそうな人がいれば出たい」という趣旨の発言をしたところ、反応があったのでさっとチームを組んで参加することにした。
3人での参加だったが、当然この組み合わせは初だった(もっというと僕以外の2人は ISUCON 自体初参加だった)。
当日までの準備
仕事が忙しかったことを主な言い訳にするが、3人揃って時間を確保して過去問を解く、といったことはできなかった。
何度か集まって話をする時間を設けることができ、そこで序盤の進め方や役割分担について話をしておいた。
また、提示された環境で(インフラ担当の方に)インスタンスを立ててもらって鍵認証で SSH 接続できること、などは確認しておいた。
当然だが、この時点で言語も選択していた。会社で使っているということもあり Ruby を選択した。
当日の動き
集合〜セットアップ
同僚との参加だったので必然的にオフィスに集まることになった。
休日はビルの施錠周りにややこしい部分があり、経験豊富な僕が解錠する役を請け負った1。
実は我々以外にもう1チーム、同じオフィスを利用するチーム2がおり、そちらの皆さんのためにもあまり遅くならないようにオフィスを開ける必要があった。
余裕をもって 8:30 頃に出社し、同じオフィスで参加する皆を迎え入れた。
並行して3人が近い席で作業できるようにディスプレイやキーボードなどをセットアップしたり、ホワイトボード、会議用モニタ + Apple TV を座席近くに集めた。
時間的には結構余裕を残して準備を終えられたと思う。
開始〜昼頃
開始してすぐに、インフラを担当してくれる方にインスタンスを立ててもらったり、鍵を配備してもらったりして、準備が整ったらまずは一度ベンチマークを走らせてもらった。
並行してもう1人の同僚が初期コードを Git で管理管理できるようにしたりデプロイ周りを整えてくれたりした。
僕はドキュメントを読み漁ったり、コードを軽く読んだりした。
ベンチマークの結果が出たあたりで一度コミュニケーションを取り、各々の初手を相談して動きを決めた。
この時間帯は MySQL のスロークエリを探して、インデックスを張ったりしていたと思う。
並行して alp での計測結果をもとに /users/transactions.json
の実装を調べたりしていたはずだ。
結局、昼過ぎの時点ではスコアに全く影響を与えることができなかった。
昼過ぎ〜夕方
正直、記憶がだいぶ曖昧で何をしていたか覚えていない。
Job を見る限りでは14時台に何度かベンチマークを実行し、 /initialize
で fail したりしていたようだ。
おそらく app と db でインスタンスを分けて、別インスタンス上の DB に接続しにいくあたりで環境変数に 127.0.0.1
が入ってしまってうまくいかないとか、そういうことをやっていた気がする。
あとログ出したいよね、という話をしていた記憶があるのでそのあたりを頑張っていたような……。
15時台になると success するようになり、ベンチマークの結果が若干上にブレたり下にブレたりしていた様子(しかし例によって記憶がない)。
夕方〜終了
最終的に MySQL のスロークエリが SELECT * FROM categories
ばかりになったので、「これ変更されないマスタデータだし、起動時に全部取得してキャッシュしようぜ」って考えてシュッと実装した。
WHERE parent_id = ?
のところはインデックスを張っていたのでスルーしたのと、 /settings
でカテゴリのリストを取得している箇所も(そのまま出力しているのが気になったので)そのままにしておいた。
このキャッシングは若干の効果があったようでチームとしてはここで初めて初期スコアを脱出した感じになった。
その後、 /users/transactions.json
のクエリ発行周りをいじって動かしてみたり SELECT *
なクエリのカラムを指定する形に変更してみたりしたが、時間があまり残っていなかったこともあり、スコアが変わらなかったりベンチマークが fail してしまう変更は結局取り込まなかった。
終盤になると、3台構成のインスタンスを app 2台、 db 1台にして app をバランシングしようとしていたが、画像アップロードの問題があり苦戦したあげく、バランシングした方がスコアが落ちてしまったので、これもやめた(結局最後まで app 1台、 db 1台で進めた)。
また、序盤から存在が気になっていた campaign
という項目の値を変化させてベンチマークを一通り動かしてみた。この項目には 0〜4 の整数が入り得ることがわかっており、5パターンのベンチマークを試して、最もスコアが出る値を入れることにした。
(このタイミングの変更としては、これが一番スコアに貢献した)
最後に仕込んでいたログを消したり、再起動してもベンチマーク通ることを確認したりして終了時間を迎えた。
雑感
問題
とても良い、そして難しい問題だったように思う。
スコアを上げるためには、ちゃんとシステムがやりたいこととやっていることを理解することが必要だったのではないだろうか。
セオリー通りにこれをやっておけばとりあえずスコアが上がる、という簡単さはあまり感じられなかった。
進め方
色々と反省はある。
- 練習不足が如実に出て、序盤の立ち上がりが遅かった
- デプロイ用にシェル書いてもらったりしたけど、ほとんど使わなかった
- バージョン管理していたけど、インスタンス上でコードいじったりもした
- バージョン管理の目的はローカルでのコード編集だけではないので、バージョン管理をしたのは良かった
campaign
の値変更はもっと早めに一度試しておくべきだった- 値によって何が変わるのかの把握が遅かった
- 実装の読み込みが浅かった
- ホワイトボード、 Apple TV を活かせなかった
一方で良かったな、と思うこともある。
- 初参加(初組み合わせ)にしてはよく動けたと思う
- 役割分担が自然にできた
- インスタンス利用やベンチマーク実施を相談しながら進められた
- その時々で、誰が何をやるかの認識合わせができた
- 終盤、戻しの判断が安全で安心感があった
- 駆け込みベンチマークでヒヤヒヤしたり、終盤で0点に怯えたりせずに済んだ
- 業務ではないのでもう少しチャレンジしても良かったとは思う
まとめると 実力不足を感じつつも、まだまだやれそうな気配もあり、悔しい思いをした といったところ。
心が折れて次回参加する流れにならないことが最も懸念していた展開だったので、チームの誰も心が折れず、リベンジの意欲を高く持って終わりを迎えられたので、それは本当に良かった。