おはようございます。名取さなにハマっている kyontan です。
チーム「hhkb」で同期3人 (自分 @kyontan, @hogashi, @h-otter) 2回目の参加で2日目で Go 実装でした。学生枠突破ならずでした、悔しい。というよりは 55,982点で全体4位の点数で落ちました。ちなみに hhkb は h-otter, hogashi, kyontan, :boom: ???? の略です。
スキルセット的には、 @h-otter がインフラ(ミドルウェア含)なんでもできる+Goの経験が一番あるマンで、 @hogashi がアプリケーションなんでもできるマンで、 @kyontan はアプリとインフラとDBを一通り見られるマンみたいな感じでした。
今回の参加に向けて、取り組んだことをつらつらと書きます。
今回は真面目に本戦に行きたかったので前々日に ConoHa で ISUCON7 の予選を解き直して練習しました。具体的には ConoHa の練習用イメージを使って 1GBプラン x3台で予選環境を再現しました。結果、10時間程度で 5,204点から509,190点まで持っていけることが分かり、計測と試行の反復を効率的に行えば ISUCON の予選は突破できるという確信を深めていました。
また、前回は最後の最後でベンチマーカを走行させた結果点数が下がって落ちたので、前回の直後に「泣きの1回はやらない」というスローガンを掲げ、1年越しでそれを達成しました。
事前に準備したのは Prometheus のサーバ (@h-otter がいい感じにやってくれた)と、やること/できることチェックリストぐらいでしょうか。だいたい大会では開始した瞬間にテンパってそのまま撃沈するのが常なので、思考停止状態でもコピペで動くようなコード片とかを用意しておくと便利ですね。あとは思考が無になったときに確認するべき事項とかを作っておくと良いのではないでしょうか? 頻繁に無になって帰りたくなりました。メンタルは大事。
例えば下のような感じです。
当日は3人がローカルで開発し、本番環境のVMへバイナリを転送して検証する、という進め方でやっていました。Go はクロスプラットフォームでのビルドがしやすいのが便利ですね。
具体的にやったことを羅列します。というか @h-otter が書いていたのを未承諾引用します。順番は適当
SELECT *
する系のクエリを必要な列しか取らないようにした/api/users
はuser_id
でreservations
を全部とってきて、アプリ側で処理してやったらめっちゃ速くなった- ここでベンチマーカが重いと言ってくるエンドポイントが
/users/:id
から/api/events/:id/actions/reserve
になった
- ここでベンチマーカが重いと言ってくるエンドポイントが
getEvent
をgetEventWithoutDetail
と分けたgetEvent
とgetEvents
を2クエリにsheets
へのクエリを消す- 効果があったのかは良くわからない
- MariaDB のチューニング
- Prometheus と Grafana で可視化
- ログインのクエリを1つに
- パスワードを平文で突っ込むようにした
- DB にインデックス張った (けどあまり良い結果がでなくてもんにょりした)
- 最初に
mysql
コマンドでインデックス張ったけど結果が全く変わらなくて、なぜ? と思ったら毎回/initialize
でテーブルを作り直していることに気がついた。
- 最初に
- IN句を使いたかったので DBにアクセスするライブラリを sqlx に切り替えた
- トランザクションの開始がおかしいところがあったので直したり デッドロック時にエラーを返さずリトライするようにした
最後は予約時のシート決定を高速化するコードが安定化しなくて入らなかったり、Redisでいい感じにやろうぜみたいなことを思うだけ思ってやらなかったりしました。多分ここができると数万点上がったはず。
あとはスコアに関係ないけど作業便利になる系として、 エラーログでソースコードの行番号を吐くようにしたり、 Makefile
弄って1コマンドでデプロイできるようにしました。
開発は3台のサーバでバラバラにやっていましたがDBは1台だけを参照するようにしました。これはDBのチューニングとかがあって、1台でやった変更を他に反映したりするのが面倒くさかったので。こうすると、やりたい人間が適当にベンチマーク対象のサーバを変更して実行してやればいいので楽でした。
ソースコードは GitHub で管理し、いい感じにやりました。コミットログは下の通りです。
数字がタグに付いていることがありますが、これはいいスコアが出た時にバイナリごとコミットしてタグつけておこうぜ、みたいな感じにした結果でした。
今回の僕の活躍はよく分からなくて、いい感じデバッグ担当だった気がします。PRを見るなりとりあえずマージしてベンチマーカを落としたりバグ探しをしていたりしました。とにかく @h-otter がぶち壊しつつ @hogashi がいい感じに安定化するコードを書いてくれてよかった感がある。
Webサーバはh2oで十分高速だし、画像のトラフィック詰まりもないしで、とにかくアプリケーションコードの改善に注力した/するしかなかった8時間でした。
最終的に残り30分でベンチマーカを叩いたところ3万点前後のスコアが5万点に若干跳ねてそこで打ち止め。一度再起動をしてブラウザからアクセスできることを確認し天命を待ったところ、無事再起動試験で落ち失格となりました。天命……
(追記: スコアが跳ねたのは、最後に実行先サーバを変えた時に インデックスを張る処理を init.sh
に書いたサーバで実行したからかもしれないことを思い出した。)
なぜ失格になったのかは分かっていなくて、おそらく /admin/api/reports/events/:id/sales
の処理が遅くて不整合が起きて落ちたのかなあなどと思っていますが、2回連続で落ちるのは運が悪かったなと……
なんやかんやでやることがなくならない8時間で、やることが見つからない8時間よりは良かったのではないかと思います。
ISUCONの予選に向けて昨日は練習をしていたわけだけど、知っていることをちゃんと愚直にできれば比較的現実的な時間で予選突破ラインには十分立てることが分かったので良かった
— kyontan@新刊はまだ (@sukukyon) September 14, 2018
イキっているなどと言われてもこれは事実だと信じていて、典型的な N+1 を潰すなどすれば予選は通過できるはずなことは分かりましたね。くぅ〜〜
来年はちゃんと本選に行けたらいいですね。頑張りましょう。
そして、参加会場を提供していただいた mixi 様、惜敗の悔しさを教えてくれる最高のコンテストを運営をしていただいたISUCONの運営の皆様、お疲れ様でした、ありがとうございました!
以下は画像です