ISUCON11予選に参加しました
2021/08/30 15:27
去年に引き続き tockn, 143 とデデデ20
というチームで ISUCON11 に参加しました
結果は、最終スコア 55684
の 65位 (600チーム中) で予選敗退でした。
事前に準備していたこと
- Makefileの整備
- 去年の問題を1回3人で練習した
Makefileの整備
secret-sauce
と名付けて色々(バックアップ、デプロイ、計測、ログローテーションとか)コマンド一発でできるように準備していました。ほとんどが去年作ったものですが、シンプルで使いやすいように改善しました。特に公開してませんが、気が向いたら公開するかもしれません。
去年の問題を1回3人で練習した
去年の反省は計測結果とかログをちゃんと見ずに “なんとなく効きそう” で変更を加えていて優先度付けができていなかったことと、ベンチが失敗しても修正をmasterに入れ続けてしまった(~ベンチが動いていない時間帯があったというのもありますが~)ということです。
今回はちゃんと計測した結果から方針を決めること ( 推測するな、計測せよ ) と、失敗したら即ロールバックして master へのコミットを止めないことを意識しました。 ブランチを指定して開発中でも環境を更新して動かせるようにもしておきました。これは結構便利でした。
計測に使ったツール
主にこのツールを使ってました。
やったこと
スコアの推移はこんな感じでした。
~11:30
最初にレギュレーション、スコア計算方法、失格条件などを3人でしっかり読みます。
確認を進めながら用意しておいたスクリプトで Nginx, MySQL (今回は MariaDB
だった) の設定ファイル (/var/nginx
, /var/mysql
) と DB の dump を取ったり、リポジトリのgit管理やスロークエリの設定を進めます。
一通りセットアップが終わった後最初のベンチマークを動かします。alp
でアクセスログ、 mysqldumpslow
でスロークエリを見て方針と作業分担を決めました。slackcat を使って計測結果を逐一 Slack へ投稿するようにしていたので確認が楽でした。
どんなクエリが実行されているのか把握するため、スロークエリは long_query_time = 0
にして全部のクエリを見れるようにしていました。1クエリのレイテンシは低いものの大量に呼ばれているクエリがあったりするので便利だと思います。
~12:30
DB の CPU がボトルネックだったのと isucondition テーブルへのスロークエリが出ていたので、 index を貼ったりクエリを改善します。
この変更でスコアが 1,000
-> 18,000
に上がりました。
アプリケーションも結構CPU使っていたので、この間に残りの2人は /trend
api とかアプリケーションのボトルネック解消を進めてくれてます。
~15:30
15:00 くらいまではあまり効果のある改善を入れられず、スコアが停滞してました。
自分はDB周りを改善した後、レイテンシが高かった(p99で1~2sくらいだった) /trend
api の修正を途中から引き継いでやっていました。
クエリが O(n^2) になっていたので、Redis の sorted set を使って修正しました。 score を timestamp に、member を id:condition にしたものをキャラクターごとに作成しました。キャラクターの数は少なかったので、それぞれ作っても問題ないと判断しました。
これで /trend
API のDBへのリクエストは無くなり、 DB のCPU使用率はかなり下がってアプリケーションの方が支配的になります。/trend
APIのレイテンシも数十ms 程度になりました。
合わせて DB のコネクション数を増やしたりいくつかチューニングして、スコアが 25,000
くらいまで上がります。
このあたりで tockn がDBに入っていたicon画像をファイルシステムに書き出す対応を入れてくれていたので、DB の cpu 使用率が減ったのにはこれも少し効いてたかもしれません。
~17:00
時間が少なくなってきたので、このあたりでサーバーを3台構成に変更します。
1 Nginx, Redis
2 app
3 MariaDB
振り返ってみると 1が結構余裕あったので、ボトルネックになっているアプリケーションサーバーを 1,2 の2台構成にしたほうが良かったかもしれません。色々ローカルキャッシュしていてすぐにはできそうじゃなかったので断念してしまいました。
~17:30
複数台構成に変更したところ、点数が1000点から伸びなくなってしまうという現象が起きてました。アクセスログを確認したところ POST /isucondition
に全くリクエストが来てなかったので、一旦作業止めて3人でマニュアルを確認します。
原因は環境変数でisuからのリクエスト先を指定するところを変更し忘れていたことで、同時並行で tockn が POST /isucondition
を非同期でバルクインサートする修正に取り掛かっていて、そちらでも点数が1000点から伸びない現象が起きていたので原因究明に時間がかかってしまいました。
環境変数を直してちゃんとリクエストが来るようにしたら、スコアが 25,000
-> 38,000
に上がりました。
このあたりでベンチマーカーが動かなくなってしまったので、取り掛かっている実装と分担を3人で整理していました。
~終了
ベンチマーカーが動くようになってから、最後に 143 がやってくれていた condition level を事前に計算して入れておく修正を入れようとしましたが、バグがあり結局入れられませんでした。tockn が進めていた isucondition のバルクインサートも結局入れられず終わってしまいました。
ただ最後にアクセスログ、スロークエリ設定、アプリケーションのログやデバッグ設定等をすべて切ってベンチを回したところ、点数が一気に 38,000
-> 50,000
まで上がります。
最後どのマシンもリソースが余っていたので、もう少し早めにログ等を切った状態でベンチを回してみれば良かったなと思います。結局 drop_probability は下げられずに時間切れとなってしまいました。
感想
去年は0点で失格だったので、ちゃんと計測してそんなに悪くない順位までスコアを挙げられたという点では成長を感じましたが、まだまだ実力不足だなと実感しました。
振り返ってみるとちゃんと改善できてスコアに効いたものが少なかったと思います。分担して効率よく改善しようとしましたがそれぞれが詰まって時間費やしてしまったので、大きめの修正は着実に優先度高いものを判断して1つずつ入れるようにしたほうが良かったなと思います。練習不足を感じました。