ISUCON14 振り返り
2024-12-08 に開催された ISUCON14 に参加した記録です。
次回以降に向けてやったことなど振り返っていきます。
去年の記録↓
tl;dr
特に何もできず惨敗でした
ベスト: 8533 最終: 2,705

メンバー
去年と同じ。ただしメンバー2は当日事情があり欠席となった。
役割としては、自分がインフラ周りをメインで見つつ飛び道具的な改善に取り組み、もう一人のメンバーにアプリケーション周りの改善を進めてもらう。
タイムライン
初動(~10:20)
- メンバー1
- ブラウザから動作確認できるように設定
- ER 図の作成
- @NotFounds
全員でマニュアル読み(~11:00)
- マニュアルを読み用語・概念確認
- 今年は SSE かあ。そこまで手が付けられるといいねーとかいう話をする
- Idempotent-Key とかは後でやれそうだねーみたいな感じ
- 点数計算
- 評価とか直接関係ないのか?
- → その後の利用に影響がある
- オーナーの売り上げとか直接関係ないのか
- → 椅子の追加とかに影響がある
- 評価とか直接関係ないのか?
ぱっとできる改善フェーズ(11:00~13:00)
- メンバー1
- Index 貼り
- alp/slp が改善するも MySQL の負荷は高い
- Index 貼り
- @NotFounds
- 少しでも DB 負荷を下げたい & 呼び出し回数が多かったので AccessToken から User/Chair を引く処理をインメモリキャッシュ → 効かない
- ActionLog
- MySQL の負荷が高いので3台目に移す → 3703 → なんか不安定になって revert
一進一退フェーズ(13:00~16:00)
- メンバー1
- @NotFounds
気づきフェーズ(16:00~)
ベンチ結果を見てユーザーの評価が一向に上がらない(すべて不満100%)なことに気づく → マッチングじゃね?となり改善を行う
- メンバー1
- /api/app/rides の N+1 改善
- マッチングでの椅子の空状態の判定処理改善 → 椅子
- @NotFounds
最終調整(17:00~)
- メンバー1
- マッチング修正
- ログを切る作業の準備
- @NotFounds
最終的に問題が解決せず、原因特定のためにこれまでのほとんどの修正を revert したうえで一台構成で終了
KPTA
Keep
- Ansible で同時にサーバーを操作したのはよかった
- 正直 Ansible にこだわりはなかったが NewRelic など重いのを入れるのは楽そうだとおもった
- しっかり書いておけば timeout とかも簡単にできるのはよいと思った
- ファイル操作と標準出力を取ってくるのはやりづらい...
- 試行錯誤のために2週間ほどほぼ毎日 AWS で環境作って壊すをやったので、これでも大分障害耐性がついた
- スコアには影響しなかったが、alp/slp計測→改善→alp/slpが改善されていることの確認はできていてよかった
- 事前に用意していた ActionLogger (ユーザーの行動分析補助)や InMemoryCache は一応生かせて良かった
Problem
- デプロイ・インフラ回り
- Ansible の実行が思ったより遅い(Gather Fact がつらい)
- Ansible を使ったことによりデプロイ処理が俗人化してしまった気がする(メンバーが使いやすいようにするところまでできなかった)
- デプロイスクリプトはかゆいところに手が届かず、結果として複数台構成の失敗につながった可能性がある 三台それぞれに対して Nginx/MySQL/Application の ON/OFF まで管理できなかった
- デプロイ→(ベンチ)→ログ解析はコマンド化していたので楽ではあったが、自分がブロックしてしまったのでよくない また、地味にログの投稿が面倒で時間が取られた
- alp/slp の diff を使ったが、main との差分ではなく、ひとつ前のベンチの結果との比較になったので正確な比較ができなかった(featureブランチ同士の比較になったりした)
- MySQL の slow query の threshold がうまく決められず SlowQuery の解析ができないときがあった(ログが吐かれすぎる)
- どのくらい Query が投げられているのか計測できておらず、MySQL の負荷の原因が突き止められなかった
- 複数台構成は練習不足を感じた
- 実装まわり
- Ruby で雑に非同期処理する方法を作れていない(Sidekiqの導入は負担が大きいので検討しなかった)
- Go だと goroutine 投げて先にレスポンス返したり、Node でも await せずにレスポンス返すみたいなことができる
- 練習で Thread 投げっぱなしにしてみたりしたけどうまく動かなかった
- なんか書き方がよくなかっただけな気もする
- SQL でできる処理なら TRIGGER 使うのがよい?
- 細かいミス(SQL の SyntaxError や Ruby の nil 参照)などは競技耐性不足を感じる
- 型のセットアップは行ったがエラーが多すぎて通すところまでできなかった
- TypeProf 使いたくなった
- (去年は Go だったけど)今年は Ruby の方が慣れているからという理由で選んだが、SQL と戯れる時間が長くてどっちでもいいのでは?となった
- Ruby で雑に非同期処理する方法を作れていない(Sidekiqの導入は負担が大きいので検討しなかった)
- その他
Try
- ログの投稿は自動化したい。もしくはダッシュボードにしたい
- ログはコミットグラフに紐づけられるようにしたい
- 1コマンドでデプロイ→ベンチ→計測までできるのが理想...
- システムのメトリクスを見ながらの改善も大事だがベンチの結果とマニュアルをよく読む
- 仕様に出てくるようなパラメータは極端な値を試してみて挙動を確認する
- データ不整合が出てきた場合ちゃんとロックされているか/トランザクションが張られているかを確認する
Action
- クリティカルエラーの原因は明らかにしておきたいので後日振り返りとしてバグ修正をやる