Continuous Batching(コンティニュアスバッチング)
LLM推論サーバーにおいて、リクエスト単位ではなくイテレーション(1トークン生成ステップ)単位でバッチを動的に再構成する手法。完了したリクエストを即座に除外し、新規リクエストを即座に挿入することでGPU利用率を最大化する。
Continuous Batchingとは
Continuous Batching(連続バッチング)とは、LLM推論サーバーにおけるリクエストスケジューリング手法の一つで、従来のStatic Batching(バッチ内の全リクエストが完了するまで待つ方式)を置き換える技術である。2023年にvLLMプロジェクトが本格実装し、以降TensorRT-LLM、SGLang、LMDeployなど主要推論エンジン全てが採用している。リクエストの到着・完了をイテレーション単位で柔軟に処理し、GPUのアイドル時間を最小化する。
Static Batchingの問題点
従来のStatic Batchingでは、バッチ内の全リクエストが生成を完了するまで新しいリクエストを受け付けられない。
具体例
4リクエストのバッチで、生成トークン数がそれぞれ10, 50, 200, 30の場合:
- リクエスト1(10トークン)は10ステップで完了するが、リクエスト3(200トークン)が終わるまで190ステップ分GPUリソースが無駄になる
- この間、新規リクエストは待機キューで待たされる
- GPU利用率は理論上50%以下に低下
| バッチ方式 | GPU利用率 | レイテンシ | スループット | 実装複雑度 |
|---|---|---|---|---|
| Static Batching | 30〜50% | 高(最長リクエスト依存) | 低 | 低 |
| Dynamic Batching | 50〜70% | 中(バッファ待ち) | 中 | 中 |
| Continuous Batching | 80〜95% | 低(即時挿入) | 高 | 高 |
Continuous Batchingの動作原理
イテレーションレベルスケジューリング
- 各推論ステップ(1トークン生成)の終了時にスケジューラが起動
- 生成完了(EOSトークン or max_tokens到達)したリクエストをバッチから除外
- 待機キューから新規リクエストを空きスロットに即座に挿入
- 新しいバッチ構成で次のイテレーションを実行
Prefill と Decode のインターリーブ
新規リクエストはprefillフェーズ(プロンプト全体の処理)が必要だが、既存リクエストはdecodeフェーズ(1トークンずつ生成)にある。Continuous Batchingではこれらを同一イテレーション内で混在処理する。
Chunked Prefill: 長いプロンプト(4,096トークン以上)のprefillを512〜1,024トークンのチャンクに分割し、decode中のリクエストとインターリーブすることで、prefillによるdecodeの遅延を防止する。SGLangとvLLM 0.5以降で実装。
実装フレームワーク別の特徴
vLLM
- PagedAttentionと組み合わせた最初の本格実装
- Scheduler が各イテレーションでバッチを動的に再構成
- Preemption(優先度ベースのリクエスト中断・再開)にも対応
max_num_seqsパラメータでバッチサイズ上限を制御(デフォルト256)
TensorRT-LLM
- NVIDIAのIn-Flight Batching(IFB)として実装
- GptManager がリクエストライフサイクルを管理
- FP8量子化との組み合わせで H100 上 Llama 3.1 70B で秒間800トークン以上
SGLang
- RadixAttention によるKVキャッシュのプレフィックス共有と組み合わせ
- Chunked Prefill がデフォルト有効
- 構造化出力(JSON等)生成時のConstraint Decodingとの統合が特徴
パフォーマンス測定
ベンチマーク環境
NVIDIA H100 80GB SXM × 1台、Llama 3.1 70B INT4(AWQ量子化)
| 同時リクエスト数 | Static Batch TPS | Continuous Batch TPS | 改善率 |
|---|---|---|---|
| 1 | 45 | 45 | 1.0× |
| 8 | 120 | 280 | 2.3× |
| 32 | 150 | 850 | 5.7× |
| 64 | 160 | 1,200 | 7.5× |
| 128 | OOM | 1,500 | ∞ |
同時リクエスト数が増えるほどContinuous Batchingの優位性が顕著になる。128同時リクエストではStatic BatchingがOOM(メモリ不足)で動作不可な一方、PagedAttention併用のContinuous Batchingは安定動作する。
実運用上の注意点
- メモリ管理: Continuous Batchingは動的なメモリ確保・解放が頻繁に発生するため、PagedAttentionなどの効率的なメモリ管理が必須
- Fairness: 長い生成リクエストが短いリクエストのレイテンシに影響しないよう、優先度制御やPreemptionの設定が重要
- Prefill vs Decode トレードオフ: Prefillが重い(長いプロンプト)場合、Chunked Prefillを有効にしないとdecode中リクエストのTTNT(Time To Next Token)が悪化
よくある質問(FAQ)
Q1: Continuous BatchingとDynamic Batchingの違いは何ですか? A: Dynamic Batchingは一定時間(例: 50ms)リクエストをバッファしてバッチを構成する方式で、バッチ実行中は新規挿入不可。Continuous Batchingは各イテレーション(1トークン生成ごと)にバッチを再構成し、完了リクエストの即時除外・新規リクエストの即時挿入が可能。
Q2: Continuous Batchingのデメリットはありますか? A: スケジューラのオーバーヘッドが各イテレーションに加算される(通常0.1ms以下で無視可能)。また実装が複雑で、KVキャッシュの動的管理(PagedAttention等)が事実上必須となるため、自前実装のハードルは高い。
Q3: ローカルのOllamaやllama.cppでもContinuous Batchingは使えますか?
A: llama.cppのサーバーモード(llama-server)はContinuous Batching相当の機能を--cont-batchingフラグで提供。Ollamaも内部的にllama.cppベースでContinuous Batchingを活用している。
まとめ
- Continuous Batchingはイテレーション単位でバッチを動的再構成し、GPU利用率を80〜95%に引き上げる
- Static Batching比で同時リクエスト数32以上の環境で5〜8倍のスループット改善
- vLLM、TensorRT-LLM、SGLangなど2026年の主要推論エンジン全てが標準採用
- PagedAttentionとの組み合わせが事実上必須で、メモリ効率とスケジューリング効率を同時に最適化