ISUCON というプログラミングコンテストに参加し予選敗退した(100位近辺でした)。
isucon.net
準備
予選の一ヶ月くらい前に、会社の同僚から「今度 ISUCON に参加しません?」という話があって、会社のメンバー三人で参加することにした。
準備として、
- Go を読み書きできるように Go Tour をやった
- 2~3日使って ISUCON 6 の予選を一人で解いてみた
- 同僚と ISUCON 6 の予選を議論した
- 当日のサーバーセットアップの準備(これは僕じゃなくて同僚がやったのだけど)
あたりをやった。
予選問題をやった感想としては、プログラムとかサーバー構成はかなり簡素だなぁと思った。
デフォルト実装はかなり荒い感じ。
だからこそ、高速化する余地あるということなんだろうけど。
ただ、競技時間8時間という時間制限はなかなかシビアだなぁと思った。
当日
予選は初日に参加。奥さんに子供の世話を頼んで、朝から会社に行った
気合い入れて 9:00 に会社に行ったら開始時間延期になって 12:00 開始の予定と言われ、暇を持て余してしまった。結局、さらに遅れて最終的に始まったのは 13:10 くらいかな。 (二日目も遅れたのはさすがに…)
競技開始直後は、3 台あるサーバーの設定を同僚にまかせて、コードを見つつ高速化ポイントを探す。
お題の Web アプリにブラウザからアクセスしてみるとアイコン画像のロードが明らかに遅い。 MySQL に画像データ入っていて毎回クエリで取り出してるようだ。それは遅いわ。
データをファイルにエクスポートし Nginx で裁くように変更。 ついでにサーバー設定も見直して 50000 点くらいになった。 ここで3時間くらい経過だったかな。
この時、ファイル名はデータの sha1 だからアイコン変更があってもキャッシュ破棄しなくていいですねーとかって話は出てたんだけど、実はうまく 304 が返ってなかったようだ。これをちゃんと 304 を返せるようになってれば高いスコアが出たらしい(検証してないから分からんけど
この後の次の一手がなかなか決まらなくて時間を浪費してしまった。 結局、「グローバルなキャッシュが欲しいよね」という話になって、急遽触ったことのない Redis を導入することに(サーバーが1台なら concurrent-map とか使うだけだけどね)。 「まぁ、Get と Set と Delete さえやっとけば大丈夫でしょ」みたいなノリでがりがり実装開始。
結局、導入したけどバグ取りに追われて気がつけば残り時間わずか。 残り10分くらいになって諦めかけたていたところ、奇跡的にバグの原因を見つける。
「これはまさか奇跡の逆転勝利ってやつかな?」と脳内で盛り上がったが、ベンチマークしてみたらスコアが下がって 40000 点くらいで FINISH でした。
よかったこと
目標は予選突破だったから「結果は出ませんでした」なんだけど、いくつかポジティブな面もあったかな。
「バグでスコア 0 点でした〜」ではなかったし、画像ファイルをエクスポートするところまでの流れは良かったと思う。
特に触ったことない Redis を導入するって決断ができたのも個人的にはよかった。 こういう思い切ったチャレンジを本番でやって、一応導入まで持っていけたっていうのは結構満足している。
こういったチャレンジがきっといつか身を結ぶのかなーなんて思ったり。
わるかったこと
二手目の Redis 導入が大した根拠なく進めてしまったのはよくなかった。
プロファイルをちゃんと見たり、スコアの計算方法を見直したり、やるべきことは沢山あった。 プロファイル用の Go ライブラリも調べてはいたけれど、今回のデフォルト実装で使ってたフレームワークと合わなくて導入を諦めてしまった。 もう少し時間を使ってでも導入するべきだったな。
スコアに反映されないのに無意味に /fetch
を高速化してしまったりしたのは典型的なダメパターンなのでかなり反省した。
最後の方はさすがに疲れてしまって明らかに頭が働いてない感じがあった。 いい仕事をするためには疲労は大敵だなーというのは改めて感じた。体力やエネルギーはうまく使わないと…。
あと、開始時間のズレとかで一人参加できなくなってしまって二人だけでやるのはちょっと辛かった面があったかな。
おわりに
結局、技術的なことぜんぜん書いてないが Technical な面はちゃんと書かれたブログが他にたくさんありますからね・・・。
とりあえず、ちゃんと 304 が返ってるかはきちんと確認しようね、っていうのは大事だなと思いました。