ISUCON10予選問題をやってみた
ISUCON11に参加登録したはいいけど何もしてないのでそろそろ何かやらねばと時間をとって過去問をやってみた。
とりあえず直近のやつをやってみるかという感じで、matsuu/vagrant-isucon を参考にしてISUCON10予選の環境をVagrant+VirtualBoxで構築した。
始める前にまず「ISUCON 事前講習2021 座学 を開催しました(資料と動画あり) : ISUCON公式Blog」の資料を読んで、ざっくりどんなことをやっていくのかを予習した。「ベンチを回して計測->ボトルネックを改善」がやるべきこと。
環境を作ってブラウザからアクセスできるようにしたら、とりあえずさっとWebサービスを触ってどんなものなのかを把握。普通にWebサービスですごいなーみたいなことを思った。
何もいじってない時点でベンチを回してみると600くらいのスコアだった。
今回はGo言語でチャレンジしてみようとチームメンバーと決めていたのでGoによる実装を眺めてみると、Webサービスの実装はmain.go
の1ファイルだけでなるほどこういう感じなんだとちょっと驚いた。
まずnginxのaccess.logをLTSV形式にするようにconfをいじって再度ベンチを回し、alpというツールで解析してみた。
解析結果をcount
, avg
, sum
でソートしたものを眺めてみると/api/estate/nazotte
というエンドポイントを改善すべきだとわかったので実装をみてみると、GISが出てきて「ウッ」となってしまった。なんもわからん…。とはいえGISのことは一旦忘れて実装を見ると、明らかにN+1があったのでまず手をつけられそうなポイントを見つけられてラッキーだった。
実際に改善に着手する前にとりあえずDBの情報もみてみるかーと思ってスキーマ情報とかレコード数とかを確認した。2テーブルしかなくてそれぞれ30000レコード。インデックスが貼られてなかったのでどっかに貼ったらいい感じになるのかなという予感があった。このときMySQLのバージョンとか気にしてなかったけど、例えばスコア改善のためにMySQL自体をバージョンアップするとかそういう方法もあるんだと知ってなるほどな〜となった。
そこからはスロークエリログを出力するようにして、mysqldumpslowとpt-query-digestというツールを使って解析してみた。whereやorder byに指定されてるカラムに適当にインデックス貼ってみて、この辺りで何度かベンチ回してみると450~550くらいで、最初からすると少しスコアが下がったいた。インデックスの貼り方でいうと、order byが昇順・降順が混ざってるとインデックスが効かないってのを知らなかったのであまり意味のない貼り方をしていたっぽい。貼った後にちゃんとexplainして確認してれば気づけたのかもしれないけど怠っていた。
とりあえず/api/estate/nazotte
の実装にあったN+1を力技(ループの分をOR条件で全部繋げるという…)で解消してみるとスコアは678に上がった。ベンチ後のアクセスログ解析でもavgは半分くらいになっていた。でもこれくらいじゃスコア全然上がらないんだなあ…ひえ〜。
とりあえずalp, mysqldumpslow, pt-query-digestを試すことができてアプリケーション側の改善とインデックス追加をやって一応スコア上げることもできたので、「ISUCON10 予選問題の解説と講評 : ISUCON公式Blog」に書いてある解説を読んで「はぁーなるほどな〜」とひとしきり感心したあと、ちゃんとインデックスを貼るのとN+1を綺麗に解消するのとbotからのアクセスを弾くやつをやってみてスコアが1158まで伸びたことを確認した。
解説を読んでみると「そんなこと思いつかなかった」と思うことばかりだったので、このままだと本番は相当やばいことになりそうだなーと思った。計測も足りてないし打ち手も全然ない。あといちいちググりながらやるので時間がかかる。本番前にあと2回分くらいは練習しておきたいところ。あっという間に本番来ちゃいそうだ。