チーム「DREAM TEAM TRIANGLE」で ISUCON12 予選に参加しました

はじめに

チーム「DREAM TEAM TRIANGLE」で ISUCON 12 予選に参加しました(通算3回)。

まずは、このような素敵な大会を開催していただいた運営様に心より感謝申し上げます。

 

今年は例年より個人的な勉強に加えて一か月半ほど前からチーム内勉強会(週末に6~8時間/回  程度)を開いて準備を行ってきました。

気合を入れて予選に挑みましたが、本番ではうまくいかないことも多く、予選敗退と辛酸をなめる結果に終わってしまいました。

ですが、得られた学びも多く、それらを次に生かすためにも今回の参加記録を残したいと思います。

チームメンバー・役割

基本的は以下の役割で作業を進めました。

<hujimori(自分)>

・マニュアル理解

・アプリケーション改修

<4423>

・チーム創設以来、じっくりコトコト煮込み続けた秘伝のタレの作成者

・deploy 環境構築

<kakuden>

・DB周りのお世話

使用したツール・言語

・Slack → スロークエリ の解析結果、top の実行結果などを通知する先 

・New Relic  → ログ解析

・Pyroscope → アプリケーションのプロファイリング

・Discord → 連絡手段

・Go → 選択した言語

Visual Studio Code → コーディング、confファイルを弄る用

今回、私たちが使用したツールの中で注目すべきは Pyroscope です。

pprof と同じようにプロファイリングができます。 そして、UI がイケています。

ISUCONの競技でインターネットを使った時 みんなpprofでプロファイリングしている時に
自分だけこれみよがしにPyroscopeにつないでCPU使用率とかを周りに見せてたこと しかも「このページって何?」って聞かれたときに「(CPU使用率が)ヤバイやつら(関数)の集会場みたいなもん」とか答えたこと さらにPyroscopeへの行き方を教えるためにヤフーでPyroscopeって検索させて でてきたリンクをクリックしてPyroscopeのトップページが表示された瞬間に そいつの耳元でWelcome to Underground」ってささやいたこと

詳細は下記を見てください。

pyroscope.io

 

最終スコア

最終スコアは 9417 でした。

順位は上から数えて 103 位でした。予選敗退とは言え、参加チーム数 600 超えの大会で 103 位という順位はまぁまぁ良いのでないかと思っています。

スコアの推移(17時点)

やったこと

10:00~11:00 準備・deploy 環境構築

<hujimori(自分)>

 問題の理解を進める。

→ 事前の勉強会で全く触らなかった SQLite に登場にビビる。

きっと、一護だって驚く

 

<4423>

deploy 環境の構築を進める。

 

<kakuden>

MySQL のバージョン、テーブルの構成を確認する。

 

11:00~12:00 準備最終段階

<hujimori(自分)>

自PCにインストールしていた Go のバージョンが古いせいでビルドエラーになることに気づく。

→ 大慌てで Go のバージョンを上げる(心臓が止まりかけた)。

 

<4423>

New Relic と Pyroscope を設定する。

→ NewRelic でログが出力されない問題が発生。

 

<kakuden>

スロウクエリにインデックスを張る。

 

12:00~15:00 本格的にチューニングを始める

<hujimori(自分)>

昼食をとる。

→ メンバー間で作業状況の確認をおこなう。

GET /api/player/competition/:competition_id/ranking が重かったので、API 内で大会のデータを毎回取得しているを部分をキャッシュしてみる。

→ キャッシュした結果、ベンチマークの整合性チェックが失敗する。

→ 終了した大会のデータもレスポンスしてしまったことが原因と分かる。

→ 解決方法が思いつかなかったので改善は断念。

 

<4423>

NewRelic でログの出力は断念。

→ tenantDB の connection pool を実装する。

public.pem を起動時に読み込むように修正する。

→ スコアが上がりだす。

 

<kakuden>

visit_history に index を張る作業を進める。

→ スコアには影響は出ず。

 

15:00~17;30

<hujimori(自分)>

POST /api/organizer/competition/:competition_id/score の for 文の中で INSERT クエリを呼び出している部分を見つける。

ソースコードを読むと、for 文の外にINSERTを切り出すだけで直ぐにBULK INSERT にできそうだと分かる。

→ BULK INSERT にする。

→ スコアが少し上がる。

 

<4423>

GET /api/player/player/:player_idをキャッシュを試みるが断念。

GET /api/player/competition/:competition_id/ranking をキャッシュする。その他いろいろな部分でキャッシュを試す。

→ 放置していた isu3 を使えるようにする。

→ 秘伝のタレ(設定ファイル)を反映する。

 

<kakuden>

isu3 を DB サーバー専用にする。

 

17;30~18;00

<hujimori(自分)>

悪あがきでマックスコネクションを弄ってみる。

→ スコア上がらず。むしろ下がる。

→ 燃え尽きる。

 

<4423>

モニタリング/デバッグ用設定を削除する。

→ スコアが上がる。

 

<kakuden>

燃え尽きる。

個人的に良かった点・反省点

良かった点

・INSERT クエリを BULK INSERT にできたこと(去年はそれすらもできなかった)。

・勉強会で事前に練習していたこと(ロードバランシング、アプリケーションサーバーとDB サーバーの分離)が実施できたこと。

・Pyroscope が見やすかった。来年も使う。

反省点

・Go のバージョンを事前に上げ忘れていたこと。

→ 準備不足。プログラミング言語に限らず競技で使うミドルウエアもバージョンは事前に確認しておくこと。

 

・マニュアルの理解が足りていない状態で、闇雲に作業をやりはじめたこと。

→ ISCUON 中にやるのはコスパが悪いのかもしれないが、アプリケーションの構成図やER図を書いてチーム内で共有しても良かったかもしれない。

 

・New Relic の操作に迷うことが多々あった。

→ 習熟度が足りない。

 

・競技時間が経過するにつれて、パフォーマンスの確認を怠りつつあった。

→ 作業に集中すると、気に掛けるなくなってしまう。。。

まとめ

私個人としてはアプリケーションの仕様を理解する能力が足りていないなと感じました。

事前学習では、N+1 の解消やキャッシュのコーディングなど、主にプログラミング面の勉強を重点的に行いました。そのせいか、予選前日までは「今回は結構やれちゃうんじゃない?」と内心調子に乗っていました。

しかし、いざ本番で問題を目の前にすると、どこから手を付けて良いか分からず途方に暮れていました。その結果、「良く分からんけど、なんとなく遅そうだからチューニングしてみる」と手当たり次第に作業を進めてしまい、スコアも大して上げることができませんでした。

ISUCON を戦う上でコーディングはもちろん、各種ミドルウェアの使い方、ログを分析するスキルは重要だと思っています。それらのスキルを活かすにはアプリケーションの仕様を理解してチューニングの方針を決めていくことが大切であると痛感しました。

 

今回の経験を糧にして、来年も頑張りたいと思います。