――ストリーミング、同時接続、スケールの現実を踏まえた “規模別ベストプラクティス”
LLMのAPIは一見「リクエストを投げてレスポンスを受け取る」だけですが、実運用では次の要件が重なります。
-
**体感速度(TTFT:Time To First Token)**を良くしたい
-
生成が数秒〜数十秒に及び、レスポンスが長い
-
**キャンセル(中断)**が必要(コストにも直結)
-
tool-call / progress / usage / error など、イベントを流したい
-
同時利用者が増えた時の接続維持コスト(FD/メモリ/LBのidle timeout/再接続嵐)
そこで候補に挙がるのが:
-
通常のHTTPS(リクエスト/レスポンス)
-
SSE(Server-Sent Events:サーバ→クライアントの一方向ストリーム)
-
WebSocket(双方向の常時接続)
※厳密には SSE も HTTPS 上で動きます。ここでは実務上の比較として
(A) 通常HTTPS vs (B) HTTPS+SSE vs (C) wss(WebSocket) という意味で扱います。
1. まずは一言でまとめる
| 方式 | 一言で言うと | LLMで向いている用途 |
|---|---|---|
| 通常HTTPS | 「送って、終わったら一回で受け取る」 | 短い応答 / 最大スループット / 運用が簡単 |
| SSE | 「1回送る → サーバがイベント/トークンを流し続ける(片方向)」 | トークンストリーミング / 進捗や状態イベント |
| WebSocket | 「1本の接続で双方向にメッセージを継続送受信」 | セッション型エージェント / リアルタイム双方向 |
2. LLM通信で重要な評価軸
LLMは “RPS(秒間リクエスト数)” だけ見ても本質を外しやすいです。特に重要なのは:
-
同時生成(アクティブな待ち) = 流入率 × 平均生成時間
-
接続維持コスト = 同時接続数 ×(FD/メモリ/バッファ/keepalive)
-
再接続嵐(障害・通信揺れ・モバイル切替)
-
キャンセルの実効性(UIキャンセルが推論停止に直結するか)
3. 機能・運用・性能の比較表
3-1. 機能(UX/プロトコル)観点
| 項目 | 通常HTTPS | SSE | WebSocket |
|---|---|---|---|
| トークンストリーミング | 可能(chunk)だが環境差が出やすい | 非常に適合(event-stream標準) | 適合 |
| イベント種別分離(token/tool/progress) | アプリで自由定義 | event/dataフレームで整理しやすい | メッセージ型で整理可能 |
| クライアント→サーバのリアルタイム入力 | 毎回HTTPで送る | 別HTTPが必要 | 同じ接続で可能 |
| キャンセル | cancel API or 切断検知 | 切断検知しやすい + cancel APIも簡単 | メッセージで即時キャンセル可 |
| 再接続/続きから再開 | アプリ実装が必要 | 自動再接続 + Last-Event-ID設計がしやすい | アプリ実装が必要 |
要点
-
SSEの固有の強みは「サーバ→クライアントのストリーミングが標準化されている」「再接続パターンが作りやすい」点です。
-
「クライアント→サーバを高頻度で送り続ける」なら、SSEは別HTTPを併用するため WebSocketの方が自然になりがちです。
3-2. 運用(大規模で壊れやすいポイント)観点
| 項目 | 通常HTTPS | SSE | WebSocket |
|---|---|---|---|
| LB/プロキシ親和性 | 最上 | 概ね良い(バッファリング/idleに注意) | 環境によっては難易度↑(upgrade/idle) |
| 接続維持コスト | 低(短いリクエストなら) | 高(ロングリビング接続) | 高(ロングリビング接続) |
| 障害時の影響 | 限定的 | 再接続嵐への備えが要る | 再接続 + セッション/状態管理が要る |
| 実装難易度 | 低 | 中 | 中〜高 |
4. 「SSEは別HTTPが必要なら、通常HTTPと大差ないのでは?」への回答
指摘は正しいです。クライアント→サーバ入力が高頻度(例えば音声のフレーム送信、タイピングごとの逐次送信等)が本質なら、SSEは「アップロードはHTTP、ダウンロードはSSE」の 2チャネルになり、同期(順序・重複・レース)管理が面倒になります。
それでもLLMでSSEが多用される理由は、LLMが典型的に 非対称 だからです。
-
アップロードは1回(プロンプト)
-
ダウンロードは長い(トークンが延々出る)
-
クライアント→サーバの追加通信は多くの場合 低頻度(cancel / regenerate / ちょっとしたcontrol)
この「下り(サーバ→クライアント)が本体」のワークロードで、SSEの価値が出ます。
5. 規模別おすすめ(1,000〜10,000,000同時ユーザ)
ここでの「同時ユーザ」は、実務に合わせて 同時にLLM結果を待っている(=アクティブ生成)ユーザ として考えます。
(単なるログイン同時数とは別です)
5-1. 規模別おすすめ一覧
| 同時ユーザ | おすすめ第1選択 | SSE/WSの使い方 | 通信観点の理由 |
|---|---|---|---|
| 1,000 | 通常HTTPS +(任意で)SSE | ストリーミング必要ならSSEを広く採用可 | 運用が簡単、UX改善の負担も小さい |
| 10,000 | HTTPS + SSE | ストリーミングUXが重要ならSSEを標準化 | ここまでならチューニングで十分回る |
| 100,000 | 非同期ジョブ(HTTPS受付)+ 状態/結果取得(HTTPS)+ SSEは選別 | “画面で待ってるユーザ”だけSSE | 10万ロング接続は可能でも運用難度が急上昇(再接続嵐、FD、メモリ、idle) |
| 1,000,000 | 非同期ジョブ中心 + pull(HTTPS) + pushは最小 | SSE/WSは極小(プレミアム/運用コンソール) | 接続だけで巨大システムになる。ストリーミングは贅沢 |
| 10,000,000 | 非同期ジョブ + キャッシュ/再利用 + 強い制限 | SSE/WSはほぼ禁止(特例のみ) | 1千万同時ストリーミングは「配信基盤」を運用する規模 |
6. 実務で強い “混合パターン”(10万以上で特に効く)
大規模になるほど、「単一プロトコルで統一」より 役割分担 が強くなります。
6-1. 定番アーキテクチャ(通信だけの観点)
| 目的 | 通信 | 例 |
|---|---|---|
| 受付(キューイング/レート制限) | HTTPS POST | POST /llm/jobs → job_id |
| 状態/結果取得(低コスト) | HTTPS GET | GET /llm/jobs/{id} |
| ストリーミング(必要なユーザだけ) | SSE | GET /llm/stream/{id} |
| キャンセル/制御 | HTTPS POST | POST /llm/jobs/{id}/cancel |
これが強い理由
-
大半のトラフィックは短いHTTPSで捌ける(高RPS・運用容易)
-
ストリーミングは “今見てるユーザ” に限定できる(同時接続爆発を抑制)
-
キャンセルは高頻度でなければHTTPで十分速い(実装も簡単)
6-2. WebSocketが本当に向くのはどこ?
WebSocketは「チャットだから必須」ではなく、次の条件で強いです。
-
入力も出力も高頻度(双方向で常に動く)
-
1セッション内に多種メッセージ(入力/トークン/ツール/状態/キャンセル)を 単一接続で制御したい
-
運用複雑度より “セッション型プロダクト価値” が大きい
7. 大規模でよく死ぬポイント(チェックリスト)
7-1. SSE/WS共通
-
idle timeout(LB/プロキシが切断)→ keepalive / ping が必要
-
バッファリング(途中の機器が溜めて一気に送る)→ ストリーム配信設定の見直し
-
再接続嵐 → exponential backoff + jitter + 制限(トークンバケット等)
7-2. LLM特有
-
キャンセルが推論停止に繋がっていない → コスト爆発
-
キューイング設計がない → 10万で崩壊しやすい(受付/待ち/完了を分離)
まとめ:規模が上がるほど「HTTPが土台、ストリーミングは選別」
-
1,000〜10,000:HTTPS + SSE のストリーミングが最もバランス良い
-
100,000:HTTPS(受付/取得)を基盤にして、SSEは “必要ユーザだけ” に絞るのが最適
-
1,000,000〜10,000,000:非同期ジョブ、キャッシュ、制限が主役。ストリーミングは贅沢品
-
WebSocketは “セッション型の双方向リアルタイム” が本質のプロダクトでのみ積極採用
コメント
コメントを投稿