学生最後のISUCON14に一人で出て30位以内に入ったと思ったら失格だった!😇
こんにちは。いや,こんいす〜!!
東京理科大学工学部電気工学科の学部4年,25卒で株式会社LayerX入社予定の@TAK848です。
12月8日に開催されたISUCON14に,学生最後の記念として(?),1人でチーム名「tak」の「tak」として参加しました。
計測ログを消してしまったので,誰向けかはさておき忘れないうちにWrite-Upを書き殴っておきます。
結果
28677点を終了前に出していたんですが,28100点くらいの点数が30位以内の賞に選ばれているのにもかかわらず,結果発表は配信のTop30には名前無し。
つまり失格ということですね!!!😅
ただ結果発表後のLeaderboardを見たところ,27位,学生5位でした!
いや,失格は失格です!
対戦ありがとうございました!!精進します!!
(追記)
あとからみたら,ちゃんと失格でした
失格の原因
計測に,前回までは秘伝のタレ+alp・pt-query-digest・pprofを頑張って使っていたんですが,今回はISUCON12・13優勝してISUCON14で作問をしているNaruseJunチーム特製のツール,pproteinを使用させていただいていました。
すごく設定が楽+使いやすい計測ツールでした。ありがとうございました!来年も使えたら使いたい。
ただこの計測サーバーのインスタンスを同じVPC内に配置していたことが原因で,多分失格になったっぽいです。
というのも,集計終了後にenvcheckを試してみたら,ちゃんと失敗したため…。
pproteinのインスタンスを削除してから試したところ成功。これだ…。
pproteinのデプロイ記事に,Cloudformationで同じVPCに!と書いてあったので完全に油断してEC2起動したままでした…残念
やったこと
気を取り直してやったことを書いていきます!
とはいっても,計測関係をpprotein用のEC2に全て載せていて,Envcheck検証時に勢いでpproteinのインスタンスのバックアップをとらずに削除してしまったので,スコアやメトリクス記録がありません!!
なんとなく思い出しながら書いていきます!
スコア推移はこんな感じでした。
リポジトリはこちらです。
爆速デプロイ&焦り
portalとcloudformationのデプロイページをどっちもArcで開いておいて,爆速デプロイを完了しました。
そしてportalからベンチマークを実行したんですが,何回やってもスコアが0で最初焦りました。
ベンチの番号,#1をとっていたので,正常に動いていたら一瞬一位だったのかなとか思ったり。
何分たっても誰もスコアあがらないからそういうことか。と思ったあたりで質問・回答コーナーにバグだと出たので,とりあえず計測環境のセットアップをはじめました。
pproteinのセットアップ
前日に,@KOBA789さん作のISUNARABEでISUCON13の素振りをしようと思い立ちセットアップしました。
ですが,pproteinのサーバーのAMIだけ作成してほぼ何も素振りせず終わっていました。ISUNARABE,本番さながら演習ができてめっちゃ良いです。推し。
ここまで前日。
とりあえず同じVPCにそのAMIを使ってpproteinをホストしました。
以下のページが良い感じにまとまっていて,基本コピペで動きました。
ただ今回,chiが使われていて,echo・gin・gorilla/muxはあったけどchiのやつはintegrationが用意されていなかったので,雑に書きました(ChatGPTが)。
良い感じに設定したり,openapiをChatGPTにぶん投げてalpのpattern書いてもらったりしていたら,計測環境ができました。ただ既に10:40でした。素振りしてれば半分にはできたかな…
マニュアル読みつつGPTs作った
とりあえずドメインに詳しいGPTs作って,分からないこと雑に聞いていました。
べんり。
インデックスを貼っていた
pproteinからslpの結果をみて,インデックスを貼っていきました。
また,ISUCON特権でPreparedStatementをオフにしました。
もうこの時点で13時くらい。(コミットログによると)
4000点くらいだったみたいです。
定石クリアに3時間。練習してれば2時間にはできた気が…。
けたたましいnotificationをなだめた
alpの結果を見るとapp・chairのnotificationエンドポイントがボトルネックになっていました。
ブラウザからアプリを開いてNetworkタブを見たら,notoficationエンドポイントにけたたましい勢いでDOS攻撃していて最初絶望しました。
ただ,マニュアルにSSE(Server-Sent Events)を使って良いと書いてあったので,調べながら実装をはじめたんですが,ChatGPTとも話して進めながらも何も知らなすぎてこの時間でやるのは無理じゃね?と思ってきました。
そこでよく見ると,通知のリクエスト間隔をレスポンスのRetryAfterから設定できることを知り,みたら30msに固定になっていたので一気に10倍の300msにしました。そしたら最終的にスコアが7000くらいへと1.7倍くらいになりました。
ISUCONのことだからどうせこれやらなくても,他潰すとスコアあがるだろうなーと思い,次に行くことにしました。
観光名所のSQLを消した
ownerのchairs取得時に,過去位置をすべて参照する豪快なクエリが走っていて,slp(slow queryログ)のトップに来ていたので,これをシンプルな1テーブル参照に変更しました。
もともとはchair_locationsテーブルで履歴全体から距離を算出していましたが,その計算結果をchairsテーブル側にキャッシュ的に持たせることで,履歴参照を不要にしました。
chair_locationsの履歴を,total_distanceとtotal_distance_updated_at取得のためだけに使われていたので,chairsテーブルにlongtitudeとlatitude,total_distanceとtotal_distance_updated_atを全て追加し,もともとのマスタデータを以下のクエリでごにょっと更新してやることで,スコアが9000くらいになりました。
やりながら多少,別テーブルにしても良かった感を感じていました。chairsのmiddlewareで不要なときも取得するようになっていたので…。
雑に初期データをUPDATEして入れたクエリ
UPDATE chairs
JOIN (
SELECT
id,
owner_id,
name,
access_token,
model,
is_active,
created_at,
updated_at,
IFNULL(distance_table.total_distance, 0) AS total_distance,
distance_table.total_distance_updated_at
FROM
chairs
LEFT JOIN (
SELECT
chair_id,
SUM(IFNULL(distance, 0)) AS total_distance,
MAX(created_at) AS total_distance_updated_at
FROM
(
SELECT
chair_id,
created_at,
ABS(
latitude - LAG(latitude) OVER (
PARTITION BY
chair_id
ORDER BY
created_at
)
) + ABS(
longitude - LAG(longitude) OVER (
PARTITION BY
chair_id
ORDER BY
created_at
)
) AS distance
FROM
chair_locations
) tmp
GROUP BY
chair_id
) distance_table ON distance_table.chair_id = chairs.id
) AS summary ON summary.id = chairs.id
SET
chairs.total_distance = summary.total_distance,
chairs.total_distance_updated_at = summary.total_distance_updated_at;
UPDATE chairs
JOIN (
SELECT
cl.chair_id,
cl.longitude,
cl.latitude
FROM
chair_locations cl
JOIN (
SELECT
chair_id,
MAX(created_at) AS max_created_at
FROM
chair_locations
GROUP BY
chair_id
) latest ON cl.chair_id = latest.chair_id AND cl.created_at = latest.max_created_at
) latest_location ON chairs.id = latest_location.chair_id
SET
chairs.longitude = latest_location.longitude,
chairs.latitude = latest_location.latitude;
唯一ブランチ切りました。一人だったんで…。
重いエンドポイントチューニング
で必要な時だけupdateかけるようにするなどのチューニングをしました。
その後さらにslpを見てindex足したりMaxConn調整したりしました。
db分割
17:30になり,流石に分けんとまずいとなり,dbを別サーバーにしました。
これでスコアが23,000くらいになりました。
その後,internalエンドポイントの処理を別サーバーになんとなく分けたつもりができてませんでした。
このあたりで,env.shにマッチング間隔のパラメータを0.5sになっていることに気づき,0.25sにしたらスコアが上がりました。
ログなどを切る
ログなどを切ったら28000が出ました。
ただしこれは最終的なもので,notificationのRetryAfterを短くするなどするとベンチが失敗することが希に発生するようになったので,600msに上げた結果です。
焦ってたのでベンチのログをよく覚えていません。
このスコアで終了を迎えました。
その他: PGO
pproteinのパワーでpgoのデータを簡単に取れたんですが,スコアがそもそも安定しきって無くて効果が見えきらなかった&3台構成にして,準備不足によりコマンド打つのがめんどかったのでやりませんでした。
こころのこり
- マッチングのアルゴリズム,DB負荷を無駄に上げていただけだったのでアプリ演算に変えたかった。距離/speedが一番近いやつをマッチするようにしたかった。DBに謎クエリ投げてボトルネックになってたし。
- マッチング間隔,雑に0.5s->0.25にしたらスコア少しあがって満足してたけど,もう少し下げても良かったかも?感想戦で試さないと分からない。
- SSE,やろうとおもったけど断念した。
- DOS攻撃,Retry時間レスポンスで変えられることに気付いて広げたらめっちゃ点数あがってそのままでヨシ!と判断した。一人だしまあ間違ってはいなかったかとは思う
- Envcheckを実行するようアナウンスあったので,余裕のあるうちにやっておけば良かった。
個人的に便利だったアプリやツール
アプリやツールの活用により,色々効率化できました。
tableplus
DBのスキーマやデータをサッと見たり編集したり書き出したりSQL実行したりと何にでも便利です。
Setappで入れています。
SSH Config Editor
これもSetappで入れられます。
.ssh/config
をGUIで編集できて,便利でした。
良い感じに編集してcmd+sで保存してくれます。IPアドレス以外埋めておきました。Port Forwardingのオプションとかいちいち覚えてられないので,すごく良かった。
pprotein,普通にローカルでホストしてRemote Forwardingすればよかった。そしたら順位出てたかな〜
chatgpt
いわずもがなです。必需品。上述のドメイン知識答えてくれるGPTsからo1, o1-miniまで。たくさん活用しました。
Cursor
複数行補完最強。
Arc
今更感ありますが。
よく見るページは全てPinしておくと便利でした。
Warp
Warpである必要はありませんが,1タブに全てのサーバーのシェルを出して,入力をSynchronize Inputで同期していました。これにより,全てのサーバーで設定まで同じ物を保っていたので簡単にサーバー分割できました。
git pull && go build -o isuride && sudo systemctl restart isuride-go
や
wget http://192.168.0.35:9000/api/pprof/data/latest -O ~/pgo.pb.gz && git pull && go build -o isuride -pgo=/home/isucon/pgo.pb.gz && sudo systemctl restart isuride-go
を,Warpの機能で何文字か売ってctrl+e,enterで実行することで,Makefile作成を完全にサボりました。makeコマンド一切使わなかった…準備不足。
/etc/以下のファイルはgit管理もせず,neovimで同時編集すれば全て同じ!と言って雑管理していました。
まあ一人参加でしたし…(main直push万歳でやった)。
謝辞
ISUCON12でコミュニティの先輩に誘われて初参加し,そこから技術力の向上に留まらず色んな縁に恵まれました。非常に思い入れ深いイベントです。
実際のプロダクト開発ではこんな雑なオペレーションは1mmも許されませんが,競技として楽しいしこれを丁寧にやっていけば実務でも使えて最高。
そして今回は新たに失格になるという思い出もできました。最近忙しすぎて,今回は気軽にサクッと出て終わるつもりが,失格前のスコアが30位以内まで行きました。
感覚は鈍るどころかインターンで実装力含め研ぎ澄まされていたのか分かりませんが,嬉しかったです。
とはいえ失格でくやしい!改め精進します!!
pproteinというすごいツールを公開してくださり作問もしてくださったNaruseJunチーム,そしてポケットサインの皆さんはじめ,運営の皆さん,参加者の皆さん,ありがとうございました!!
問題,結構分岐ポイントがあってボリューミーで面白かったです。当然ですが,複数人で出たら効率良いだろうなと思いました。
残りの学生生活・そして新卒1年目も頑張っていきます。
それでは,おついす〜
Discussion