Share
Embed
ISUCON作問入門/ ISUCON Summer Fes 2023
FUJIWARA Shunichiro
August 26, 2023
Transcript
34 slides
-
@fujiwara (Twitter, GitHub, Bluesky) 面白法人カヤック SREチーム ISUCON (1,2,5,11) (6) (4)
運営4回 (3,8,12,13) 代表作 github.com/kayac/ecspresso Amazon ECS デプロイツール -
用語集 実は統一された用語集がない(!?)ので今回の発表内での定義 問題 = お題、参照実装、初期実装とも 選手が高速化するWebサービス(アプリケーション)を指す 作問者 = ISUCONの問題を作る人 選手
= 競技者とも。ISUCONに参加する人、問題を解く人 -
作成するWebアプリケーションの形式 昔: HTMLを返すWebアプリケーション (ISUCON 5,6あたりまで) 今: JSONを返すWebAPI (ISUCON 7以降) 画面はSPA的に分離することが多くなった
今時のアプリケーションはHTMLを返さないことが多い ベンチマーカーがHTMLを解釈するコスト(CPU)が高い HTMLはテンプレート編集時にうっかり壊しやすい レギュレーションで「見た目を変更しないこと」があると… どちらでもよいが、いっそJSON APIだけでもいいのでは…? -
Webフレームワーク / ORM ISUCONの初期実装でよく使われているもの Go: Echo Ruby: Sinatra Python: Flask
Node.JS: Express 移植の都合上、比較的シンプルなものが選択される ORMは使わないことが多い (SQLを直接書く) 自分らが馴染みがあるものを使うのもよいのでは Railsがメインな企業ならRailsで、などやってみてほしい -
アプリケーション/ミドルウェアの起動方法 1. systemdから直接プロセスを起動 言語ランタイムをOSに直接インストールする必要がある 2. Docker(Compose)で起動 OSに言語ランタイムを用意しなくてよい 過去にはどちらの例もあるが… 選手が楽なのは直接起動 作問者が楽なのはDocker
nginx, mysqldなどは直接起動、アプリケーションだけDockerというのもあり 社内なら特定プラットフォーム(クラウド)を前提にできる コンテナ、サーバーレス、FaaSなどでやるのもあり(やってほしい!) -
例題 - GitHub Gistのようなサービス POST /api/login ログイン POST /api/logout ログアウト
GET /api/gists 自分のGist一覧 GET /api/gists/:id Gistの詳細 POST /api/gist Gistの作成 public, privateが選択できる GET /api/all_gists すべての(他のユーザーのものを含む)Gist一覧 publicなもの+自分のprivateなものが時系列順に並ぶ これで6 API。物足りなければ とか編集・削除とかコメントとか機能追加すればよい -
問題とベンチマーカーと初期データ生成器をセットで実装する ISUCONと普通のWebアプリのテストの違い ISUCONの問題は「パフォーマンスに問題を抱えている」必要がある → それなりの規模の初期データが必要 ベンチマーカーは問題のDBを参照できない → 問題に含まれる要素は選手が管理する。ベンチマーカーがアクセスできない 「初期データ生成器」によって以下を用意する それなりの規模のデータセット
ベンチマーカーが使う事前知識 既存ユーザーの認証情報 初期データに含まれる内容(検証用にサンプリングしたもの) これがないと「初期データを全部消す」チートが可能になってしまう -
例題(Gistみたいなやつ)で生成する初期データの例 ユーザー情報 (認証情報を含む) ユーザーが投稿したgistの情報 // users [ {"id":1,"name":"tagomoris","password_digest":"..."}, {"id":2,"name":"941","password_digest":"..."}, ...
] // gists [ {"id":"af3aece0d","user_id":1,"title":"...","content":"...","is_private":true,"created_at":"..."}, {"id":"cc6125c19","user_id":2,"title":"...","content":"...","is_private":false,"created_at":"..."}, ... ] faker系のライブラリを使うなどして作りましょう -
ベンチマーカーは何で書く? (実装言語) Goで書く ISUCON 3以降、ほぼ全てのベンチマーカー実装はGo https://github.com/isucon/isucandar (ISUCON10以降で採用) ISUCON本 付録B にisucandarの使い方が書いてあります!
既存の負荷試験ツールで書く たとえば Grafana K6 https://k6.io/ ISUCON本 4章にk6の使い方が書いてあります! あなたの好きな言語で書く 高速・大量の並行処理が必要なので言語によっては大変かも… -
作問の流れ 1. WebアプリケーションのAPI仕様、DB構造を決める 2. 初期データ生成器を作る 初期実装用のDBに取り込めるデータを出力 ベンチマーカーの事前知識(JSONのファイル)を出力 データセットのサイズはあとで調整するので可変できるように 3. Webアプリケーションを実装する
4. 実装した仕様を満たしているか確認するE2Eテストシナリオを書く これがベンチマーカー(の一部) 事前知識を元にして検証を行う -
ベンチマーカーの実行フェーズ 最近のISUCONベンチマーカーの動作は2フェーズに分かれている 1. 整合性チェックフェーズ 問題アプリケーションが仕様を満たしているかを検証する 途中で失敗したら負荷走行しないで終了する(競技体験のため) i. 問題の initialize APIを呼び出して初期状態にする
ii. 事前知識を元にしてE2Eテストを実行する ここで全てのAPIを網羅する 2. 負荷走行フェーズ i. 複数のシナリオを平行で走らせて、問題に負荷を掛ける ii. 規定時間(大抵は1分)に達する、打ち切り条件(エラー数など)になるまで実行 iii. スコアを算出して終了 -
例題の整合性チェックフェーズのシナリオ例 1. POST /api/login でログイン 2. GET /api/gists で自分のGist一覧を取得 3.
GET /api/gists/:id で自分のGistの詳細を取得 × n 4. POST /api/gist でGistを作成(private) 5. GET /api/gists で自分のGist一覧を取得 4.で作成したGistが含まれていることを確認 6. GET /api/gists/:id で 4.で作成したGistを取得 7. GET /api/all_gists ですべてのGist一覧を取得 4.で作成したGistが含まれていることを確認 8. POST /api/logout でログアウト 9. GET /api/all_gists ですべてのGist一覧を取得 4.で作成したGistが含まれていないことを確認(privateなので) -
整合性チェックでチェックすべきこと 正常系のリクエストに対して正常なレスポンスが返されるか 異常系のリクエストに対して仕様通りのレスポンスが返されるか (例: ログインしていない状態でprivate gist一覧は出ない) どちらも仕様に対して網羅的にやる必要がある 特に異常系のチェックを念入りに キャッシュしてはいけない内容をキャッシュしてもpassするような穴になるため 「ベンチマーカーが仕様違反を検出しない」=「結果は有効」
ベンチマーカーを常に正としておかないと結果の判定に恣意的な解釈が入ってしまう (とはいえ身内向けなら、最悪ごめんなさいで済むかも) -
負荷走行フェーズでやること 整合性チェックシナリオを最低1個走らせておく 複数平行で実行した場合に壊れないように注意 データを作成→一番最初に反映されている のような判定は危険 同一ユーザーのシナリオを同時に回すと競合が発生しやすいので避ける 整合性チェックよりもチェックが緩い/単純なシナリオを複数走らせる 厳密にチェックしているとベンチマーカーの負荷が高くなることがある とはいえステータスコードとタイムアウトぐらいはちゃんと見る スコアをカウントする
失格(fail)条件で打ちきる failの場合、1分を待たずにすぐ終わったほうが競技体験がよい 条件はレギュレーションに明示しておくこと -
選手に負荷を選択させるかどうか(昔話) ISUCON 3,4では選手が負荷を選択できた ( -workload オプション) 何並列でリクエストを送るか(を指数化したもの) 結論からするとあまり良くない(ので廃れた) そもそも設定があることに気が付かない ずっと低い負荷のままで競技が終わってしまった人が…
チューニングせずworloadを変えて試してしまう人が出る そこでガチャをされても困る 極端に大きいworkloadを指定することでベンチマーカーの挙動がおかしくなり 謎に高いスコアが出る不具合(を突いた人がいた) 境界値をチェックするべきとはいえ… -
ポータルはどうする? 本物ISUCONのポータルは大変高機能 1000人以上の参加者でスムーズな運営をするためには必要なので… 参加登録、チームメンバー管理 GitHub/Discordのアカウント連携 競技用サーバーを起動するためのCloudFormation Template ベンチマーカーの実行 結果の集計、表示をするダッシュボード clar(clarifications)のやりとり
運営側のチーム管理機能 ISUCON 10〜12で使われたもの https://github.com/isucon/portal/ 動かすのは相当大変(Rails, MySQL, Redis, SQS...) 身内向けにはオーバースペック -
最小限のリモートベンチマークWebアプリケーション 1. POST / を実装する リクエスト元IPアドレスに対してベンチマーカーを実行する ./bench -target http://{ リクエスト元IP
アドレス}/ ベンチマーカーの標準出力をHTTPのレスポンスにして返却する 2. 選手は競技サーバーで curl -XPOST http://{ ベンチマーカーのアドレス}/ ベンチマーカーの実行結果がレスポンスで返ってくる! ベンチマーカーは別プロセス(バイナリ)で外部コマンド呼び出しするのを推奨 ベンチマーカーは不意に(実装の不備で)死ぬことがある 組み込んでしまうと死んだ場合の結果を選手に返せない