ISUCON10予選通過しました ~ チームMN
概要
2020年9月12日に開催されたISUCON10予選にチーム名「MN」で参加して、予選順位14位で本選出場を決めました (2年ぶり2回目)。
ISUCONとは?
ISUCON10とは、「いい感じにスピードアップコンテスト (Iikanjini Speed Up Contest)」の略称です。3人までのチームを組んでWEBサービスのパフォーマンス改善の腕を競い合うコンテストです。今年で10回目の開催となるISUCONですが、私個人は3年前のISUCON7から毎年参加しています。
チーム紹介
今年7月のISUCON10参加登録のアナウンスを受けて、社内Slackで一緒に参加するメンバーを募集しました。結果、↓の3人ともISUCON経験者のチームが結成できました。
予選までの準備
今年は去年の予選敗退のリベンジに燃えていました。チームを結成した7月から練習と開始していきます。
- ISUCON 夏期講習2020 座学 https://www.youtube.com/watch?v=PyY7M7qK6QA
- ISUCON9予選・本選のマニュアルとレギュレーションの読み合わせ
- 予行演習2回 ISUCON9本選・ISUCON7予選
特に本番を模した8時間の予行演習は、チーム内の役割分担の意識強化や競技開始直後のオペレーションの効率化につながり、予選突破のために一番有効だったと思います。
今回はレギュレーションなどから Ubuntu サーバーで複数台構成であることが予見できました。効率的に①ベンチマーク → ②ボトルネック解析 → ③チューニングのイテレーションを行うため、以下のような作業環境をあらかじめ作成して本番に挑みました。
作業構成
共有の作業用サーバーをパブリッククラウド上に構築して、ビルドとデプロイ、パフォーマンス解析はすべてを行えるような環境を構築しました。ローカルPCで作業する場合に対して、チーム3人が環境を共有できるところがメリットです。
パフォーマンス解析には、netdata、kataribe, pprof の他、独自の SQL 実行時間集計ツールやダッシュボードを開発しました。
予選当日
12:15ごろ (競技開始)
競技開始直後はベンチが実行できませんでした。デプロイ環境の構築や初期設定、データベース解析など、練習どおりのオペレーションを実施しました。
13:15ごろ~ (開始から01:00~)
はじめてベンチが実行できました。初期スコアは480点でした。
beppu4 の活躍で、早々に MySQL サーバーとアプリサーバーの分離が終わっていました。 netdata からボトルネックが MySQL の CPU だと判明しました。総実行時間が大きいクエリーに注目してインデックスを設定してきます。
estateテーブルはアプリケーションの仕様としてデータ更新はなく新規追加しかないため、/api/estate/low_priced がオンメモリキャッシュ化を実装しましたがベンチが通らず revert しました。
okabeeeat のデータベース解析結果から、 estate と chair の2つのテーブルはアプリ的に関連性がないことが分かり、サーバー B を estate 専用 DB、サーバー C を chair 専用 DB にすることにしました。
16:00ごろ~ (開始から03:45~)
データベース分割によりスコアが977点まで上昇します。それでもまだ MySQL の CPU がボトルネックでした。
この頃「ORDER BY popularity DESC, id ASC」のクエリーが目立っていたので、estate に popularity DESC, id ASC のインデックスを生成したのですが、活用されずに悩んでいました。苦し紛れに popularity DESC のみ ORDER 句を修正してスコアを1306点に上げます。
抽出レコードの全件数の取得に同じ条件でSELECT COUNT(*) していたので、CALC_FOUND_ROWS を使って高速化しました。スコアが1521点に向上。
17:30ごろ (開始から05:15)
なぞって検索の N+1 クエリーを最適し、スコアが1857点に向上。
Geo 関連は知見がなかったため、競技時間内での最適化は無理と判断しました。
18:00ごろ (開始から05:45)
緯度・経度などにさらにインデックスを追加、スコアが2600点に向上。上位チームがFailしたこともあり、一時的にトップに踊り出ました。しかし、この時間帯あたりからベンチが Fail することが目立ち始めます。
19:00ごろ (開始から06:45)
16:00ごろ実施した「ORDER BY popularity DESC, id ASC」の変更を revert しました。初期バリデーションでエラーになることが増えてきたためです。スコアが2200点くらいまで減少しました。
Critical エラーの原因となっていた、 postEstateリクエストのタイムアウトを解消するため、1件づつ発行していた物件 INSERT クエリーをまとめて1回で実行するよう修正しました。これによりスコアが2500~2700点で安定しました。
20:00ごろ (開始から07:45)
他チームのスコアが見えなくなり、そろそろ競技終了が近づいていました。2500点以上なら予選通過できそうと判断して、クロージング作業に入りました。ログ出力の停止やパフォーマンスデータ出力コードの削除、再起動設定確認などです。
最後にスコアガチャを行い 20:30ごろに 2676点 でフィニッシュしました。
良かった点
チームとして模擬演習どおりの動きができたことが最大の勝因だと思います。それぞれの準備した役割を十分に果たすことができました。用意したパフォーマンス解析ツールによりボトルネックを発見し適切に処置できたことも勝因です。
おまけ
リポジトリ: https://github.com/hirosuzuki/isucon10-qual
利用したツール
- Visual Studio Code … Go言語アプリ開発
- netdata … 秒単位のサーバー負荷監視ツール
- kataribe … アクセスログ解析
- make … タスクランナー
- slack … コミュニケーション
- Google SpreadSheet … 情報共有
- https://github.com/hirosuzuki/go-isucon-tracer … SQLログ出力
- https://github.com/hirosuzuki/isucon-viewlog … パフォーマンス解析ダッシュボード
Discussion