😶‍🌫️

ISUCON14にチームOL001として参加しました(インフラ編)

2024/12/20に公開

Introduction

この記事は、OPENLOGI Advent Calendar 2024 の20日目の記事です。

ISUCON14にチームOL001のインフラ担当として参加してきました。

最高スコアは9987、最終スコアは失格になってしまい、提出できたとしても ISUCON14 受賞チームおよび全チームスコア では130位程度のスコアでした。

当記事ではインフラ担当としての下準備と当日対応したことについて自分のメモも兼ねて書いていきます。

関連記事

ISUCONとは

ISUCONとは いい感じにスピードアップコンテスト というパフォーマンスチューニング大会です。

競技時間は8時間、運営からEC2サーバをN台(N=3のことがほとんど)与えらえ、EC2内に入っているソースコードやミドルウェアを改善するオンラインゲームです。

運営側が用意しているベンチマーカーを回すことによってスコアを出すことができ、競技終了前にEC2をすべて再起動して最後に回したEC2サーバに対してベンチマーカーを回して最終スコアを出しています。

言語は Node.js/Ruby/Python/Rust/PHP/Perl から選べ、DBなどのミドルウェアだいたいの場合はnginxとMySQLだが、実際に本番開始するまで何が動いているのか分かりません。

チームメンバー

昨年同様、同僚の @noko がチケット争奪戦に勝ったので参加できました。

去年と同じメンバーで、社内でも同じ開発チームなのでコミュニケーションはスムーズに進みました。

名前 役割 参加経験
@noko アプリケーション 3回目
@yshir アプリケーション 2回目
@takeokunn インフラ 2回目

目標

去年のISUCON13の反省を踏まえて、今年は以下の4つの目標を立てました。

どのような形であれ確実に提出し失格にならないようにする

ISUCON14 レギュレーション を満たしたうえで、当日マニュアル に記載されている「最終スコア」の手順をすべて通過したチームのみランキングに載ることができます。 どんなに途中良いスコアを出そうと最終で失格になっては何の意味もないので、今年も確実に提出することが目標でした。

事前の手順書を洗練させ、アプリケーション担当が改善に集中できる体制作りを強化する

前回は初参加ということもあり、本番に相当あたふたしてしまいました。

  • ISUCON13ではenv回りの扱いや初期構築をミスってしまい改善を阻害してしまった
  • 手順書に細かいミスが多かったので本番漏れが生じてしまった

自分の仕事はアプリケーション担当が快適に開発を回せるように準備をすることです。 今回は手順書を洗練させてフルに時間を活用できるようにするのが目標でした。

上位チームと同等のツール選定をする

前回はとりあえず上位チームが使っていそうなツールを入れて、なんとか開発を回したという反省がありました。 上位チームと改善環境の差分を可能な限りなくすことによって、アプリケーション改善部分で勝負できるようにしました。

  • 上位チームがどういうツール選定をしているのか調べる
  • そのうえで現状使いこなせそうな必要なツールのみに絞る

サーバ分割方法を用意する

インフラ担当が大きくスコアを伸ばすにはサーバ分割をしなければならないということに去年気がつきました。 どういう対応が必要なのか、どういう手順でやるとよいのか、上位チームはどういう判断で分割しているのかというのをちゃんと調査し、本番で使えるようにすることが目標でした。

  • appを2台にする
  • DBシャーディングをしてDBを2台にする

事前練習

練習時間

2024年11月初旬〜2024年12月8日の約1ヵ月、約60〜80時間程度練習に費しました。

練習 時間
通し練習 8時間 × 2回 = 16時間
個人練習 40〜60時間程度

今年はチーム内で合同練習をせずに個人練習のみで、直前1週間前と前日に通し練習をしたのみで練習量が少なかったです。

「ISUCON常勝軍団の頭の中〜メンバー集めから解き方の秘密まで〜」視聴

「ISUCON常勝軍団の頭の中〜メンバー集めから解き方の秘密まで〜 (2024/11/14 12:00〜)」をオンライン視聴しました。

https://findy.connpass.com/event/334902/

去年の自分達のチームはpprofを活用できていなかったが、それ以外のツール選定はそんなに違わなかったので安心しました。

「サーバ分割(app1台、mysql1台)みたいに分割した所でスコアが伸びない場合はどうアプローチしていけばよいですか?」という質問に対して以下のような返事をいただきました。

  • そもそもCPUかメモリを使い切れてない
  • 複数台にした時のレイテンシはボトルネックにならない

参加ブログからは読み取れない上位チームの肌感覚を知りたかったので自分としては大満足なイベントでした。

個人練習

手順書最適化

今回は@conao3とEmacsのorg-modeをフルに使って手順書を作成しました。

https://gist.github.com/takeokunn/002b687d985b5b2af30feeadac892352

  • org-mode でタスク管理をする
  • org-tangle で必要なファイルをプロジェクト内に展開する
  • org-babel でEC2にssh keyを展開する

また、今年は自分のPCをすべてNixに移行したので mazrean/isucrud をNixでパッケージングしました。

https://github.com/takeokunn/nur-packages

ツール選定

以下の対応をしました。

  • 不要なツールの削除
    • 去年はGitHub Actions上でAnsibleを流せるようにしてたけど不要なので削除
    • Netdata は結局イマイチという結論になった
  • Ansible最適化
    • 不要な記述の削除
    • READMEを修正
  • before_bench高速化
    • shell script作成
  • pprof導入

ツールとしては以下を使いました。

ツール 役割 memo
alp nginx集計
htop メトリクス監視
gh GitHub API Client
sqldef DB Schema管理 今回は使っていない
tig Git Client
pt-query-digest Slow Query
pprof Goプロファイラ
tbls スキーマ可視化 GitHub Actionsで回している

どんな構成であれ、MySQLとnginxに移行して改善を回すということを事前に決めていたので、上位チームの秘伝のタレを拝借して事前に準備しておきました。

キャッシュはRedisを使わずに catatsuy/cache を使っていたようなので一応準備してたRedisは不要でした。

https://github.com/catatsuy/cache

サーバ分割

サーバ分割をする為に、おおよそ以下の2つの方法があります。

  • nginxでappを2台に分割
    • 特定の重いエンドポイントだけ分ける
    • ラウンドロビン
  • シャーディングをしてMySQLを2台に分割

nginxの検証はどちらにせよやった方がよいだろう、ということで手元で nginx.conf の書き方をあらためて検証しました。

また、シャーディングは narusejun/isucon12-final の実装が分かりやすく、db clientを分割する手法ということが分かったが、練習が不十分でうまく使えそうにないということで今回は見送ることにしました。

https://github.com/narusejun/isucon12-final/blob/master/app/webapp/go/db.go

過去問

isucon9-qualify

https://github.com/isucon/isucon9-qualify

isucon9-qualify を本番1週間前に8時間みっちりやりました。

サーバ分割もうまくいき、9位程度のスコアを出すことができました。

https://docs.google.com/spreadsheets/d/1PUMn9hgJ45GptUjPiBJY3ZrdsgHYgsRqpVNWQoDJnss/edit?gid=1255494876#gid=1255494876

{"pass":true,"score":16260,"campaign":0,"language":"Go","messages":[]}

isucon13

https://github.com/isucon/isucon13

去年の問題で体を温めておこう、ということでisucon13を本番前日4〜5時間ゆるくやりました。

スムーズに改善を回せる確認ができ、手順書としては十分に準備できていることを確認ができました。

本番

開始直後

11時半ころには以下のテンプレ行動が終わりました。 手順書通りにやったらノーミスでここまできたので安心しました。

  • ssh configを用意してサーバに入る
  • GitHubで管理できるようにサーバでGit Pushする
  • ansibleを完走する
  • DBをセットアップしてtbls
  • READMEにレコード数やisucrudの結果を記述する
  • go-jsonライブラリの差し替えなど定型行動する
  • 本番用の nginx.conf や MySQL config を用意する

中盤

アプリケーション担当が改善を回すのを眺めつつ、以下のような細かい修正をしました。 今回は手順書がちゃんとしてたのもあり、サーバでのトラブルは一切起きなかったのでとにかく暇でした。

  • nginxで返せそうな静的リソース対応
  • alp微修正など

Goの練習を一切してなかったというのもあり、時間的にものすごく余ってしまったので、2人の活躍を祈るしかありませんでした。 ひたすらベンチマーカーが落ちまくって全然改善が進まずにひたすら苦しい時間が続いていました。

一応暇だったので Server Side Events をGoでしてみるかと試してたんですが、全然歯が立たなかったです。

提出間際

サーバ分割手順書も作って、いつでも分割できるようにできるようにしてたものの、1台でさえ提出直前に謎にベンチマーカーが落ち続けるという問題が起きました。

1回目はベンチマーカーが通るのに2回目は落ちる、といったことが多発したが結局何が問題だったのか分からずに祈るように提出。

結局最終ベンチで落ちてしまいました。

反省

事前に立てた目標に対しての結果は以下です。 下準備としては自分なりにはできたつもりですが、本番はうまくいかなかったというのが現実です。

目標 下準備 本番
最終提出 ×
手順書改善
ツール選定
サーバ分割 ×

今回手順書を最適化したことによって本番中にかなり時間が相当余ってしまいました。 インフラ担当として「ボトルネック以外の雑多な対応を可能な限りすべて対応する」という信条でいたのですが、ほぼ手順化できたのでボトルネックに来年以降はちゃんと向き合っていきたいと思っています。

GitHubで編集を提案

Discussion