$30 off During Our Annual Pro Sale. View Details »

ISUCON作問入門/ ISUCON Summer Fes 2023

ISUCON作問入門/ ISUCON Summer Fes 2023

FUJIWARA Shunichiro

August 26, 2023
Tweet

More Decks by FUJIWARA Shunichiro

Other Decks in Technology

Transcript

  1. ISUCON作問入門
    2023.08.26 ISUCON夏祭り 2023
    @fujiwara 藤原俊一郎

    View Slide

  2. @fujiwara (Twitter, GitHub, Bluesky)
    面白法人カヤック SREチーム
    ISUCON (1,2,5,11) (6) (4)
    運営4回 (3,8,12,13)
    代表作 github.com/kayac/ecspresso
    Amazon ECS デプロイツール

    View Slide

  3. 今日の目標
    「聞いた人が社内/身内ISUCONを作って開催するぞという気持ちになること」
    実際に開催されると泣いて喜びますのでぜひ報告を…

    View Slide

  4. 用語集
    実は統一された用語集がない(!?)ので今回の発表内での定義
    問題 = お題、参照実装、初期実装とも
    選手が高速化するWebサービス(アプリケーション)を指す
    作問者 = ISUCONの問題を作る人
    選手 = 競技者とも。ISUCONに参加する人、問題を解く人

    View Slide

  5. ISUCONの構成要素
    問題
    Webアプリケーション(サービス)の言語実装
    データベースやWebサーバーなどのミドルウェア、OSが動くサーバー
    ベンチマーカー
    問題に対して負荷を掛けてスコアを計測するプログラム
    ポータル
    選手がベンチマーク実行をリクエストするWebアプリケーション
    結果を保存、表示する
    レギュレーション
    ルール、スコア計算方法など
    作問者が作るもの = 全部

    View Slide

  6. 作問について
    「過去のISUCONでよくある例」を踏まえて
    身内のISUCONを作るにはこうしてもいいんじゃない? という話をします

    View Slide

  7. 問題のネタ・テーマ
    ISUCON12予選 マルチテナント
    ISUCON12本選 スマホゲーム
    自分達が苦しんでいること、過去に
    苦しんだこと、社内のシステムや
    サービスをネタにすると考えやすい
    とはいえISUCONという競技を楽し
    みたいのであれば、題材はなんでもよい

    View Slide

  8. View Slide

  9. 作成するWebアプリケーションの形式
    昔: HTMLを返すWebアプリケーション (ISUCON 5,6あたりまで)
    今: JSONを返すWebAPI (ISUCON 7以降)
    画面はSPA的に分離することが多くなった
    今時のアプリケーションはHTMLを返さないことが多い
    ベンチマーカーがHTMLを解釈するコスト(CPU)が高い
    HTMLはテンプレート編集時にうっかり壊しやすい
    レギュレーションで「見た目を変更しないこと」があると…
    どちらでもよいが、いっそJSON APIだけでもいいのでは…?

    View Slide

  10. 問題の規模
    API数は多くても10〜15程度(20あると相当大規模)
    DBのテーブル数は一桁個(10個越えると多すぎ)
    選手が把握しきれない、コードを読み切れない
    作問者がつらい(単純に量が多い)
    変な穴ができる可能性が増える(やたら稼げてしまうポイントなど)
    なるべく機能を絞り込んでシンプルに

    View Slide

  11. Webフレームワーク / ORM
    ISUCONの初期実装でよく使われているもの
    Go: Echo
    Ruby: Sinatra
    Python: Flask
    Node.JS: Express
    移植の都合上、比較的シンプルなものが選択される
    ORMは使わないことが多い (SQLを直接書く)
    自分らが馴染みがあるものを使うのもよいのでは
    Railsがメインな企業ならRailsで、などやってみてほしい

    View Slide

  12. データベース
    過去問はMySQLがほとんど (ごく稀に PostgreSQL, SQLite)
    MySQLを普段使っていないなら自分らが馴染みがあるものを使うほうがよい
    正規化はわりとちゃんとされていることが多い
    非正規化するとパフォーマンス上有利になりがち
    正規化されているとN+1問題を作りやすい

    View Slide

  13. アプリケーション/ミドルウェアの起動方法
    1. systemdから直接プロセスを起動
    言語ランタイムをOSに直接インストールする必要がある
    2. Docker(Compose)で起動
    OSに言語ランタイムを用意しなくてよい
    過去にはどちらの例もあるが…
    選手が楽なのは直接起動
    作問者が楽なのはDocker
    nginx, mysqldなどは直接起動、アプリケーションだけDockerというのもあり
    社内なら特定プラットフォーム(クラウド)を前提にできる
    コンテナ、サーバーレス、FaaSなどでやるのもあり(やってほしい!)

    View Slide

  14. ISUCON問題によくある技術要素
    DBにインデックスがない
    primary keyしかないのでフルスキャンが多発する
    N+1問題
    ループ中でSQLを発行するので大量のクエリが飛ぶ
    不適切なコマンド呼び出し
    system()
    などで不要な外部コマンドを呼び出す
    あまり不自然に重く、汚く書く必要はない
    知識が少ない人が素朴に書いたらこうなっちゃいました、ぐらいがよい

    View Slide

  15. 問題について ここまでのまとめ
    問題はシンプル/小規模に
    いっそ画面はなくてもいいのでは…?
    正直、API仕様だけでも競技できる気がする…
    普段馴染みのある技術で作ってよい
    フレームワーク、データベース、クラウドなど
    過去のISUCONが使った技術に縛られる必要はない
    実装は素朴にしておく
    変な罠とかは考えないでよい

    View Slide

  16. では実際に作っていきましょう
    = Webサービスの高速化コンテスト = 機能を壊さずに高速化するコンテスト
    問題
    パフォーマンスがよろしくないが機能的には問題ないWebサービス
    ベンチマーカー
    問題に対して負荷を掛けてスコアを計測するプログラムだが
    機能が壊れていないか検証するE2Eテストでもある
    両方セットで開発していく必要がある

    View Slide

  17. 例題 - 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。物足りなければ とか編集・削除とかコメントとか機能追加すればよい

    View Slide

  18. 問題とベンチマーカーと初期データ生成器をセットで実装する
    ISUCONと普通のWebアプリのテストの違い
    ISUCONの問題は「パフォーマンスに問題を抱えている」必要がある
    → それなりの規模の初期データが必要
    ベンチマーカーは問題のDBを参照できない
    → 問題に含まれる要素は選手が管理する。ベンチマーカーがアクセスできない
    「初期データ生成器」によって以下を用意する
    それなりの規模のデータセット
    ベンチマーカーが使う事前知識
    既存ユーザーの認証情報
    初期データに含まれる内容(検証用にサンプリングしたもの)
    これがないと「初期データを全部消す」チートが可能になってしまう

    View Slide

  19. 例題(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系のライブラリを使うなどして作りましょう

    View Slide

  20. ベンチマーカーは何で書く? (実装言語)
    Goで書く
    ISUCON 3以降、ほぼ全てのベンチマーカー実装はGo
    https://github.com/isucon/isucandar (ISUCON10以降で採用)
    ISUCON本 付録B にisucandarの使い方が書いてあります!
    既存の負荷試験ツールで書く
    たとえば Grafana K6 https://k6.io/
    ISUCON本 4章にk6の使い方が書いてあります!
    あなたの好きな言語で書く
    高速・大量の並行処理が必要なので言語によっては大変かも…

    View Slide

  21. 作問の流れ
    1. WebアプリケーションのAPI仕様、DB構造を決める
    2. 初期データ生成器を作る
    初期実装用のDBに取り込めるデータを出力
    ベンチマーカーの事前知識(JSONのファイル)を出力
    データセットのサイズはあとで調整するので可変できるように
    3. Webアプリケーションを実装する
    4. 実装した仕様を満たしているか確認するE2Eテストシナリオを書く
    これがベンチマーカー(の一部)
    事前知識を元にして検証を行う

    View Slide

  22. ベンチマーカーの実行フェーズ
    最近のISUCONベンチマーカーの動作は2フェーズに分かれている
    1. 整合性チェックフェーズ
    問題アプリケーションが仕様を満たしているかを検証する
    途中で失敗したら負荷走行しないで終了する(競技体験のため)
    i. 問題の initialize APIを呼び出して初期状態にする
    ii. 事前知識を元にしてE2Eテストを実行する
    ここで全てのAPIを網羅する
    2. 負荷走行フェーズ
    i. 複数のシナリオを平行で走らせて、問題に負荷を掛ける
    ii. 規定時間(大抵は1分)に達する、打ち切り条件(エラー数など)になるまで実行
    iii. スコアを算出して終了

    View Slide

  23. 例題の整合性チェックフェーズのシナリオ例
    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なので)

    View Slide

  24. 整合性チェックでチェックすべきこと
    正常系のリクエストに対して正常なレスポンスが返されるか
    異常系のリクエストに対して仕様通りのレスポンスが返されるか
    (例: ログインしていない状態でprivate gist一覧は出ない)
    どちらも仕様に対して網羅的にやる必要がある
    特に異常系のチェックを念入りに
    キャッシュしてはいけない内容をキャッシュしてもpassするような穴になるため
    「ベンチマーカーが仕様違反を検出しない」=「結果は有効」
    ベンチマーカーを常に正としておかないと結果の判定に恣意的な解釈が入ってしまう
    (とはいえ身内向けなら、最悪ごめんなさいで済むかも)

    View Slide

  25. 負荷走行フェーズでやること
    整合性チェックシナリオを最低1個走らせておく
    複数平行で実行した場合に壊れないように注意
    データを作成→一番最初に反映されている のような判定は危険
    同一ユーザーのシナリオを同時に回すと競合が発生しやすいので避ける
    整合性チェックよりもチェックが緩い/単純なシナリオを複数走らせる
    厳密にチェックしているとベンチマーカーの負荷が高くなることがある
    とはいえステータスコードとタイムアウトぐらいはちゃんと見る
    スコアをカウントする
    失格(fail)条件で打ちきる
    failの場合、1分を待たずにすぐ終わったほうが競技体験がよい
    条件はレギュレーションに明示しておくこと

    View Slide

  26. ベンチマーカーの並列度
    「負荷走行中に並列度を動的に変化させるかさせないか」
    正直これは派閥がある
    「ベンチマーク」== ある負荷に対しての性能を計測するもの なので
    ベンチマーカーが動的に負荷を変化させてはいけないよ派
    初期実装の遅い状態でちゃんとスコアが計測できつつ
    最後数百倍に高速化した状態でスコア差がつく負荷を与えるためには
    並列度を動的にコントロールしないと無理じゃない?派

    View Slide

  27. 並列度固定派の実装で気を付けること
    クライアントは負荷走行中の最後までタイムアウトしない
    タイムアウトでの減点や失格をしない
    「5秒でレスポンスを返さないとエラー、エラー10個でfailです」
    【理由】
    極端に遅い初期実装に対して大量の固定負荷を掛けると
    長時間かかるレスポンスが多発する
    初期実装でfailしてしまうと選手が改善する手がかりが得られない
    シナリオで送るリクエスト間には意図的なsleepを入れずに
    レスポンスが届いたら即次のリクエストを送るように実装する

    View Slide

  28. 動的負荷可変派の実装で気を付けること
    「5秒以内にレスポンスを返すこと」のような仕様を設けておく
    一定時間内にタイムアウトが発生しなかった場合
    並列度を増加させるようなロジックを組む
    タイムアウト発生=過負荷とみなしてそれ以上並列度を増やさない
    シナリオでリクエストを送る場合
    ユーザーの実際の行動を模した間隔を開けてリクエストすることができる

    View Slide

  29. 選手に負荷を選択させるかどうか(昔話)
    ISUCON 3,4では選手が負荷を選択できた ( -workload
    オプション)
    何並列でリクエストを送るか(を指数化したもの)
    結論からするとあまり良くない(ので廃れた)
    そもそも設定があることに気が付かない
    ずっと低い負荷のままで競技が終わってしまった人が…
    チューニングせずworloadを変えて試してしまう人が出る
    そこでガチャをされても困る
    極端に大きいworkloadを指定することでベンチマーカーの挙動がおかしくなり
    謎に高いスコアが出る不具合(を突いた人がいた)
    境界値をチェックするべきとはいえ…

    View Slide

  30. ポータルはどうする?
    本物ISUCONのポータルは大変高機能
    1000人以上の参加者でスムーズな運営をするためには必要なので…
    参加登録、チームメンバー管理
    GitHub/Discordのアカウント連携
    競技用サーバーを起動するためのCloudFormation Template
    ベンチマーカーの実行
    結果の集計、表示をするダッシュボード
    clar(clarifications)のやりとり
    運営側のチーム管理機能
    ISUCON 10〜12で使われたもの https://github.com/isucon/portal/
    動かすのは相当大変(Rails, MySQL, Redis, SQS...) 身内向けにはオーバースペック

    View Slide

  31. ポータルを低コストでなんとかする
    身内向けISUCONで最低限必要な機能は2個だけ!
    1. ベンチマーカーの実行
    2. 結果の集計、表示をするダッシュボード
    これだけなんとかする
    logicaさんのRemote-BMIもどうぞ!
    https://github.com/logica0419/remote-bmi

    View Slide

  32. 最小限のリモートベンチマークWebアプリケーション
    1. POST /
    を実装する
    リクエスト元IPアドレスに対してベンチマーカーを実行する
    ./bench -target http://{
    リクエスト元IP
    アドレス}/
    ベンチマーカーの標準出力をHTTPのレスポンスにして返却する
    2. 選手は競技サーバーで curl -XPOST http://{
    ベンチマーカーのアドレス}/
    ベンチマーカーの実行結果がレスポンスで返ってくる!
    ベンチマーカーは別プロセス(バイナリ)で外部コマンド呼び出しするのを推奨
    ベンチマーカーは不意に(実装の不備で)死ぬことがある
    組み込んでしまうと死んだ場合の結果を選手に返せない

    View Slide

  33. 最小限のダッシュボード
    ISUCONの結果 == スコア(数値) なので
    「メトリックを収集できるなにか」にスコアを送信してグラフを書いてやればよい
    Amazon CloudWatchで実装した例 (カヤック社内ISUCON 2022)

    View Slide

  34. 身内向けISUCON作問のまとめ
    問題はシンプルに
    APIだけでもよいと思います
    普段馴染みのある技術で作ろう
    本物ISUCONに縛られなくてもよい
    ベンチマーカーは……頑張って!
    今のところISUCON本が世界で唯一の作問者向け解説本です
    ポータルは最低限でなんとか
    (ネタ帳にあったけど入らなかったこと)
    /initialize問題, password hashの話, スコアの配点...

    View Slide