vLLM KV Cache 內存不夠怎麼辦:顯存、上下文和併發排查

vLLM 提示 KV Cache 內存不足時,優先降低 max_model_len,再調整 gpu_memory_utilization、併發和批處理;本文說明 FP8 KV cache、手動緩存大小、CPU offload 與常見 OOM 排查。

vLLM 啓動時出現下面這類報錯,通常不是模型權重下載壞了:

1
The model's max seq len ... KV cache is needed, which is larger than the available KV cache memory

它表示:模型權重、運行時開銷佔掉顯存後,剩下的空間不足以爲你設定的最大上下文長度準備 KV Cache。最直接的處理順序是:先降低 --max-model-len,再檢查併發,最後才考慮提高顯存利用率、量化 KV Cache 或擴容。

不要一上來就把 --gpu-memory-utilization 拉到 1。那樣可能讓 vLLM 通過初始化,卻在真實請求、CUDA graph 或其他進程搶顯存時更容易 OOM。

先理解:KV Cache 爲什麼會佔滿顯存

模型權重決定“模型能不能加載”,KV Cache 決定“模型能同時記住多少 token、服務多少請求”。每生成或讀取一個 token,注意力層都需要保存對應的 Key/Value 狀態。

因此 KV Cache 佔用會隨下面幾項增加:

  • max_model_len:允許的最大上下文越長,緩存需求越大。
  • 併發請求數:每個併發會佔用自己的上下文空間。
  • 模型結構:層數、KV head 數、hidden size 和數據類型都會影響緩存大小。
  • 緩存精度:默認通常跟隨模型數據類型;FP8 等低精度緩存可節省空間,但有兼容性和質量邊界。

最容易忽略的是併發。即使每個請求只給 8K 上下文,多個請求同時運行時,KV Cache 的總需求仍會快速增長。

先從日誌判斷是哪一種問題

啓動日誌通常會給出三個關鍵信息:

  1. 模型聲明或你配置的最大序列長度。
  2. KV Cache 需要多少 GiB。
  3. 當前可用於 KV Cache 的實際空間,以及 vLLM 估算出的可行最大長度。

如果日誌說“最大長度 32768 需要 10GiB KV Cache,但當前只有 4GiB”,不要先糾結模型是否支持 32K。模型支持不代表你的這張卡能在當前配置下服務 32K 請求。

先記下日誌提供的估算最大長度,把第一次測試設置在它的 60% 到 80% 左右,再逐步提高。

第一優先級:降低 --max-model-len

這是成功率最高、影響最可預測的調整。比如模型原生支持 32K,你的實際業務只處理普通對話、短代碼和小文檔,可以先從 8K 開始:

1
2
vllm serve Qwen/Qwen3-8B \
  --max-model-len 8192

如果仍然不足,再試:

1
2
vllm serve Qwen/Qwen3-8B \
  --max-model-len 4096

不要把模型卡標稱的 128K、256K 或更長上下文直接寫進服務參數。對於單卡部署,真實可用長度取決於權重、顯存、併發與緩存精度。

一個實用的起點:

顯存與用途 先試的上下文長度
12GB–16GB 單卡、8B 級模型 4096 或 8192
24GB 單卡、7B–14B 模型 8192 或 16384
24GB 單卡、30B 級量化模型 先從 4096 開始
長文檔/RAG/多用戶服務 根據日誌估算與壓測決定,不要照表硬套

這些數值是排障起點,不是顯存承諾。不同模型的 KV Cache 大小可能相差很大。

第二優先級:限制併發和批處理

服務能啓動,不代表高併發時一定穩定。先把併發控制在小值:

1
2
3
vllm serve Qwen/Qwen3-8B \
  --max-model-len 8192 \
  --max-num-seqs 4

--max-num-seqs 限制一次迭代可處理的序列數。數值越大,吞吐可能更高,但 KV Cache 和調度壓力也更大。

如果請求裏經常帶長 prompt,還要關注 --max-num-batched-tokens。它決定一次調度最多處理多少 token;過高可能讓 prefill 階段瞬間佔用更多資源。排障時先保持保守,確認穩定後再逐步放大。

建議按這個順序壓測:

  1. 單請求、4K 上下文,確認服務穩定。
  2. 單請求、8K 上下文,觀察首 token 延遲與顯存。
  3. 兩個併發請求,確認不會 OOM。
  4. 再逐步增加 max_num_seqs 或批處理 token 數。

不要同時調整上下文、併發、batch 和模型量化,否則很難定位哪一個參數造成爆顯存。

第三優先級:合理設置 --gpu-memory-utilization

--gpu-memory-utilization 指定當前 vLLM 實例可使用的 GPU 顯存比例,取值在 0 到 1 之間。vLLM 會根據這部分空間規劃權重、運行時和 KV Cache。

例如:

1
2
3
4
vllm serve Qwen/Qwen3-8B \
  --gpu-memory-utilization 0.90 \
  --max-model-len 8192 \
  --max-num-seqs 4

當報錯明確說“可用 KV Cache 太少”且 GPU 上沒有其他進程時,可以小步提高,例如從 0.90 試到 0.920.94。每次只加一點,並用真實請求測試。

以下情況不建議硬拉高:

  • 同一張卡上還跑着桌面程序、另一個推理服務或訓練任務。
  • 啓動後可用顯存會波動。
  • 使用 CUDA graph、視覺模型或高併發 prefill 時容易出現峯值。
  • 你已經遇到運行過程中的 CUDA OOM,而不只是初始化檢查失敗。

如果多實例共享同一張 GPU,應爲每個實例留出明確預算,而不是都設置成 0.9。

FP8 KV Cache:省顯存前先確認模型和版本

vLLM 支持通過 --kv-cache-dtype 改變緩存數據類型。CUDA 11.8+ 環境可使用 FP8 相關選項,例如:

1
2
3
vllm serve Qwen/Qwen3-8B \
  --kv-cache-dtype fp8 \
  --max-model-len 16384

FP8 KV Cache 可以顯著減少緩存佔用,但不要把它當成完全無代價的開關:

  • 先確認當前 vLLM、CUDA 與硬件支持該數據類型。
  • 模型檢查點是否提供合適的 KV scale,會影響結果;缺失時需要謹慎評估。
  • 長上下文、複雜推理、工具調用和結構化輸出都應與默認緩存精度做對照測試。
  • 如果只是爲了讓一個不合適的大模型塞進顯卡,先降低上下文或換更合適模型通常更穩。

所以更推薦的順序是:先用默認精度把 4K/8K 跑穩,再測試 FP8 是否真的能讓業務獲得所需的上下文或併發。

手動指定 KV Cache 大小時要知道優先級

較新的 vLLM 提供 kv_cache_memory_bytes,可按每張 GPU 的字節數精確指定 KV Cache 大小。它適合多服務共卡、需要固定顯存預算的場景。

要注意:顯式設置緩存字節數時,會覆蓋通過 gpu_memory_utilization 自動推算緩存大小的行爲。不要同時把兩者當作疊加增益;先決定是採用“比例預算”,還是採用“固定緩存預算”。

固定預算適合運維約束明確的服務器,單機排障則通常先用 --gpu-memory-utilization--max-model-len 更直觀。

CPU offload 能解決什麼,不能解決什麼

新版 vLLM 支持把一部分 KV Cache offload 到 CPU,或結合 LMCache 等後端處理緩存層。這可以在 GPU 緩存不夠時擴展容量,但代價是 PCIe/內存傳輸和延遲。

它更適合:

  • 偶爾出現超長上下文請求;
  • 業務能接受更高首 token 延遲;
  • 有充足系統內存,並已做真實壓測;
  • 想爲長 prompt 做降級路徑,而不是追求最高吞吐。

它不適合拿來掩蓋“模型權重本來就放不下”的問題,也不能替代對併發和上下文上限的管理。若所有請求都頻繁換出換入,吞吐往往會明顯下降。

一個可複製的排障模板

先從保守配置啓動:

1
2
3
4
vllm serve Qwen/Qwen3-8B \
  --gpu-memory-utilization 0.90 \
  --max-model-len 4096 \
  --max-num-seqs 2

確認能穩定處理單請求後,按下面順序調整:

1
2
3
4
5
4096 上下文稳定
-> 8192 上下文稳定
-> max_num_seqs 从 2 调到 4
-> 调整 max_num_batched_tokens
-> 再测试 FP8 KV Cache 或 CPU offload

每輪記錄四項數據:可用 KV Cache token 數、首 token 延遲、生成 tokens/s、峯值顯存。這樣才能判斷某項優化是在提升吞吐,還是隻是把 OOM 推遲到更高併發時發生。

常見誤區

誤區一:模型支持長上下文,所以服務必須開滿

模型能力上限和你的顯卡可服務上限是兩回事。服務端的 max_model_len 應按硬件和業務上限設置。

誤區二:把 gpu_memory_utilization 設成 1 就能解決

這會減少安全餘量,不能減少 KV Cache 本身的需求。運行時峯值反而更容易觸發 CUDA OOM。

誤區三:只降低權重量化,不管併發

權重量化能騰出顯存,但併發與上下文仍會讓 KV Cache 迅速膨脹。服務配置必須同時限制長度和請求數量。

誤區四:CPU offload 一定比拒絕長請求好

如果延遲敏感,頻繁 offload 可能比明確把長請求路由到更大顯存節點更差。先定義業務的延遲和成本邊界。

總結

vLLM KV Cache 內存不夠,最可靠的處理優先級是:

1
2
3
4
5
降低 max_model_len
-> 限制 max_num_seqs 与 batch
-> 小步调整 gpu_memory_utilization
-> 验证 FP8 KV Cache
-> 最后考虑固定缓存预算或 CPU offload

先讓一個短上下文、低併發配置穩定工作,再按業務數據逐步擴大。只要把模型權重、KV Cache、併發和真實上下文長度分開看,大多數“內存不夠”問題都能更快定位。

參考:

记录并分享
使用 Hugo 建立
主題 StackJimmy 設計