パフォーマンスとスケーリング
2026年10月27日、単一のGoサーバーでWebSpaceの認証済みWebSocket接続10,000件と、予定したイベント100,000件すべての配信を確認しました。SQLite3の混合負荷でも、10,000接続を維持したまま書き込み1,000件と読み取り10,000件を完了しました。
検証結果と各回の測定データ(JSON)をダウンロードできます。Workspaceチャットとは別に、WebSpace専用のリアルタイム経路を試験した結果です。
試験環境と設定
| 項目 | 試験条件 |
|---|---|
| 試験日 | 2026年10月27日、韓国標準時 |
| サーバー | Intel Core i9-14900K、論理CPU 32個、RAM約62.6 GiB、Goプロセス1個 |
| ストレージ | NVMe SSD(SHPP41-2000GM)、WSL2仮想ディスク(ext4)、Ubuntu 26.04 |
| 負荷生成 | 同じマシン上のNodeプロセス4個、ループバックIP 4個、認証アカウント1個 |
| 通信 | ローカルループバック。外部ネットワーク、TLS、本番プロキシは対象外 |
| SQLite3 | WAL、synchronous=NORMAL、busy timeout 5秒、読み取り接続最大8個、DBごとの単一書き込みキュー |
| WebSocket上限 | サーバー全体・DBごとに各12,000接続、IPごとに10,000接続、接続ごとに毎秒10,000メッセージ |
| HTTP上限 | 読み取り・変更・ハンドシェイクそれぞれIPごとに毎秒20,000リクエスト、バースト30,000件 |
試験専用の開発ビルドでライセンス等級の検査を迂回しました。認証、権限、Originの検査は通常のWebSpace経路で行いました。DBはディスク上のext4に保存し、メモリファイルシステム(tmpfs)は使用していません。負荷生成側で読み取りの送信速度や同時書き込み数を制限していません。
HTTP上限は、サーバー設定のwebspace.rateLimits.read、webspace.rateLimits.mutation、webspace.rateLimits.handshake配下のrequestsPerSecondとburstを指定し、再起動して適用しました。試験値は既定値と異なります。リアルタイム接続の上限はサービスと容量で管理します。
5,000接続から10,000接続までの配信
各接続がイベント10件を受信する条件で、規模ごとに3回測定しました。すべての回で配信の欠落、重複、別の部屋への誤配信は0件でした。
| 認証済み接続 | 各回の配信成功 / 予定 | 全接続の準備時間 | イベント配信p95 |
|---|---|---|---|
| 5,000件 | 50,000 / 50,000件 | 1.25秒 | 110 ms |
| 7,500件 | 75,000 / 75,000件 | 1.77秒 | 183 ms |
| 10,000件 | 100,000 / 100,000件 | 2.66秒 | 312 ms |
時間は3回の測定値の中央値です。接続準備時間には負荷生成プロセスの起動、段階的な接続、認証と購読の完了を含みます。配信p95はイベントの送信から受信までの時間の95パーセンタイルで、各回のp95の中央値を示しています。9月の試験では接続ごとに10件すべてを受信するまでの時間を測っており、遅延を直接比較できません。
SQLite3の書き込み1,000件と読み取り10,000件
認証済み10,000接続を維持しながら、共有リソースの状態変更1,000件とHTTP読み取り10,000件を同時に開始しました。書き込みはDBごとのキューで順番に処理します。
| HTTP読み取りの同時リクエスト設定 | 測定回数 | 書き込み成功 | 読み取り成功 | 混合負荷の完了時間 |
|---|---|---|---|---|
| 128件 | 3回 | 各回1,000 / 1,000件 | 各回10,000 / 10,000件 | 中央値2.69秒 |
| 10,000件 | 1回 | 1,000 / 1,000件 | 10,000 / 10,000件 | 3.11秒 |
完了時間は接続準備後、読み書きを開始してからすべてが完了するまでです。同時リクエスト10,000件という設定はクライアント側の発行条件を表し、SQLiteが10,000クエリを同時実行したという意味ではありません。読み取り接続プールは最大8個です。
読み取りはすべてHTTP 200で応答し、HTTP 429と書き込みエラーはありませんでした。同時リクエスト10,000件の試験では、書き込みp95は858 ms、読み取りp95は約2.88秒でした。4つの試験DBすべてで固有の操作1,000件、リソース値100,000→99,000、バージョン1,000、報酬数1,000を確認しました。SQLiteのintegrity_checkはいずれもokでした。
接続維持、部屋の分離、再接続
10,000接続に対し、イベント10件を12回送信し、各回の間に5秒待機しました。約67.27秒で1,200,000件すべてを配信し、欠落や重複はありませんでした。100接続を強制切断して再接続した後も、後続イベント10,000件をすべて受信しました。
別の試験では、100部屋に100接続ずつ分けました。初回の100,000件をすべて配信し、別の部屋への誤配信はありませんでした。20秒の待機後と100接続の再接続後の配信も通過しました。全15試験で観測したサーバーRSSの最大値は約1.50 GiBでした。試験終了後の残存接続は0件でした。
遅延とストレージ経路の影響
接続維持試験では、購読領域全体のトークンを再検証する周期と重なった回で、配信p95が約1.91~2.31秒まで増えました。短時間の配信試験で得た312 msは、持続的な遅延の保証ではありません。
WSLのWindows共有ファイルシステム(9p)を利用した先行試験では、同時書き込み1,000件のうち414件だけが完了し、残りは5秒の書き込み待機・トランザクション制限内に完了しませんでした。上記の成功結果は同じNVMe SSD上のWSL ext4仮想ディスクで得られたものです。ストレージへのアクセス方式によって結果が変わる場合があります。
既定の読み取り上限であるIPごとに毎秒500件・バースト1,200件では、読み取り37件がHTTP 429になりました。最終試験はリクエストを遅くする代わりにHTTP上限を引き上げて測定しています。
負荷に合わせた構成
| 処理の形態 | 検討する構成 |
|---|---|
| 単一サーバー、社内ツール、キューで処理できる書き込み | SQLite3で実際の読み書き比率を使った負荷試験 |
| 多数の部屋・リソースへの継続的な書き込み | PostgreSQLまたはMySQL/MariaDBを検討 |
| 複数サーバーとレプリケーション | 外部DBとサーバー間イベント配信を検討 |
| リアルタイム配信の遅延 | 部屋の人数、メッセージサイズ、ファンアウト、認証再検証の負荷を確認 |
キューは同時書き込みの順序を整えますが、処理量には限りがあります。今回の接続数は同一アカウントの認証済みソケット数です。異なる10,000ユーザーの一連の操作や、長時間続く負荷を検証した数値ではありません。本番環境のTLS、プロキシ、外部ネットワーク、実際の処理比率を含めて追加測定してください。
運用中は運用状況でリクエスト、エラー、応答時間、DBの状態を確認できます。一連のユーザーフローはリアルタイム五目並べゲームを作るのサンプルで確認できます。