ISUCONに初参加しました(ISUCON11)
ISUCONは与えられるwebサービスの性能をどれだけよくできるかを競うコンテストです。今年に入ってからwebに関わるコードを書いたり今月からweb系インターンに行き始めた自分ですが、web知識の幅を増やそうと考えて参加してみました!
チームメンバーは店長さん(@_shop_one)とlongrunさん(@1on9run_zun1027)でした。ICPC横浜の懇親会で喋ったのもあって声かけやすかった競プロer、かつISUCON出場経験はないが出てみたいという同じくらいの熱量を持っていた2人です。アプリの言語としてはGoを使いました。
想定読者はISUCON出たことないぜ!みたいなフォロワーや、web何も知らないで初めてISUCON出る学生が最初は何したか気になる人です。
過去問練習!
ISUCON公式からハンズオンや座学があったので、何の知識も持たないで行ったらよくわかりませんでした。
このまま本番じゃやばい!というのもあって練習としてまず個人でISUCON7予選を、次にチームでISUCON10予選を解きました。環境を作るのも慣れてなくてまあまあ大変でしたが、Dockerをごにょごにょしてたら作れました。
座学ではプロファイリングツールを入れてどこが悪いか調べろ、と言っていたのでalpとpprofを入れました。公式のREADME見て苦戦しながら入れるも動かない、Dockerを再起動したら動く、などの苦戦を伴ってプロファイリングツールに慣れていきました。
そしていざ改善をしようと思っても何をしたらいいかわからなかったので、公式解説を見に行ったり強そうな人がブログにまとめた記事とか読んでN+1問題を潰すとか画像をキャッシュする?とかを学びました。
DBにインデックスをはる、とか複数サーバに処理を分散させる、とかはどう行うのかわからないままで当日を迎えました。
予選当日!
~11:00 サーバに接続したりする
予選本番です。始まっていざサーバ3台があるのに対し、どうやって実装とかを進めていく?という話になりました。強いチームは1台でアプリの改善をして、他の台ではDBの改修をしてというように分けるのだと思いましたが、そんなことできないな~という話にもなり3人がそれぞれ別々のサーバで改善を進めていくことになりました。
サーバにはsshで接続します。ところで普段の自分はWindowsのWSL環境なのですが、ssh接続したサーバに対しvscode上で開発がしたいと考えていました。これをするにはWSLを閉じてWindows側にsshの鍵を置き、そっちからsshをすると上手くいきます。最初はわからなくて苦労しました。
次にこれをGitHubに上げるところで苦戦しました。ssh先でgit configのnameとemailを設定したらpushができるようになりましたが、鍵とかがどうなっていたのかはよくわかっていません。isuconユーザのホームディレクトリにwebappやら設定ファイルやらが置いてあり、webapp以下の使用する言語の実装をGitHubに上げることにしました。リポジトリは下のものです。
~12:00 プロファイリングツールを入れる
練習同様alpとpprofを入れよう、ということをしました。pprofは
$ go get -u runtime/pprof $ go get -u net/http/pprof $ apt install graphviz
をたたいて、goのコードでimportに1行とmain関数に数行足せば使えるようになります(たぶん)。main関数には
runtime.SetBlockProfileRate(1) runtime.SetMutexProfileFraction(1)
と下のコマンドに現れる/debug/pprof/*を受け付けるようなものを足せばよいです。
そして
go tool pprof -http=0.0.0.0:1080 isucondition https://isucondition.t.isucon.dev/debug/pprof/profile
をしてベンチを走らせれば動きました。isuconditionというのはgoのバイナリで、その後ろのURLはアプリのものです。-httpは分析結果をブラウザで見るために指定しています。ベンチはコンテスト中だと選手用ページからボタンを一つ押せば走らせることができました。
これを見て重いところを改善するぜ!と、ようやくISUCONが始まった感じがしました。
12:00~ 改善に向けて取り組む
pprofを見ているとgetTrendやpostIsuConditionが重そうだったのでその辺りの改善から始めました。その辺りでコードの改善をしたらどうやって変更を反映するんだ?ということに気づきました。自分はわからなかったのですが、チームメンバーがmain.goをコンパイルし直した後でsudo systemctl restart --now isucondition.go.serviceしたらいいよと教えてくれました。終わってから気づいたのですが、質問としても投稿されていたみたいでした。
その後、自分は16時半くらいまでgetTrendと格闘していました。実行時のエラーログをどこから見るのか調べるのに苦労したり、Goの経験の浅さから思ったように書けなかったことが原因です。エラーログは、
journalctl -b | grep "db error"
で見ることができました。
その間、チームメンバは画像を静的ファイルにするべくnginxをいろいろいじったり、DBのindexをあちこちに貼ってくれたりと格闘していました。そうやって諸々をしていたのですが、5000点~9500点あたりをうろうろしているだけでした。
終了直前
最後にベンチを実行したサーバにて、終了後にシステムテストのようなものが走ります。誰のサーバが1番点数出る?みたいなことを試しつつ、プロファイリングツールを消して最終提出を行いました。
感想
途中トラブルが発生したための延長もあって、ほぼ9時間のコンテストとなり非常に疲れました。練習してきたことが刺さらずに点数が伸びず終了直後は辛い気持ちでしたが、翌日に発表された最終スコアで1万点をこえていたので今は嬉しい気持ちです。
ISUCON11 オンライン予選 全てのチームのスコア(参考値) : ISUCON公式Blog
参加登録時点ではGoを書いたことがなく、SQLも授業でやったくらいで全然覚えてないぜ!みたいな状態でした。そこからGoやSQLを勉強したり、過去の参加記を読んだりしていろいろ勉強しましたが、これから勉強するとよさそうな知識の入り口はいろいろ見えるようになりました。チームでの予選時の目標は達成できなかった(おそらく598チーム中306位)のですが、当初の参加目的である知識を広げることは達成です。
今月や来月はweb系企業でインターンをしているので、次に出るISUCONではもっと良い成績を取れるように力をつけたいです💪