
大模型應用后端底座設計與高并發支撐并發時先看資源邊界當大模型LLM應用的用戶規模從幾十個內部測試人員暴增到上萬并發請求時后端架構師面臨的挑戰與傳統 Web 系統完全不同。傳統 Web 微服務處理一個 HTTP 請求耗時通常在 20ms 以內而大模型推理一個請求可能持續數秒甚至數十秒同時占用沉重的 GPU 顯存KV Cache。并發流量一旦涌入如果不加控制地把請求全量塞給推理引擎如 vLLM 或 TGI系統不會只是緩慢排隊而是會直接觸發 GPU 顯存 OOM 崩潰或者導致首字延遲TTFTTime To First Token暴漲到幾十秒讓絕大多數用戶因超時而放棄連接。并發上來之后后端底座的第一條防線應是基于 KV Cache 物理容量估算與 TTFT 要求的自適應背壓控制。為什么大模型后端的并發瓶頸在 KV Cache在傳統 API 后端中內存瓶頸通常在 JVM 堆內存或 Go 堆內存。但在 LLM 推理 Server 中真正的命門在于GPU KV Cache 顯存容量。每一次 Context 交互模型在 Transformer 注意力層都需要為歷史 Token 維護 Key-Value Cache。一個 70B 參數的模型在 FP16 精度下單用戶 4096 長度的 Context 就要占用近 2GB 的 KV Cache 顯存。flowchart TD UserReqs[突發 500 個并發 LLM 請求] --|1. 涌入 LLM Gateway| Gateway[LLM Backend Gateway] Gateway --|2. 檢查當前 GPU KV Cache 占用| Evaluator{KV Cache 占用率 85%?} Evaluator -- 是: 觸發背壓守住線 --|3. 啟動優先級拒絕| PriorityQueue[Priority Load Shedding] PriorityQueue --|VIP 用戶請求| ExecQueue[壓入 待推理隊列] PriorityQueue --|普通 / 匿名請求| FastReject[直接返回 429 System Busy] Evaluator -- 否 --|4. 放行給推理引擎| vLLMEngine[vLLM Inference Engine] vLLMEngine --|5. PagedAttention 動態分配| GPUCache[GPU 物理顯存 KV Cache] ExecQueue -- vLLMEngine即使采用了 PagedAttention如 vLLM 架構顯存能夠實現細粒度的物理頁復用顯存總容量依然決定了系統能夠同時進行 Prefill首字填充和 DecodeToken 生成的物理并發上限。一旦并發數超過了這個物理極限vLLM 引擎不得不將部分請求的 KV Cache 搶占并 Swap 到 CPU 內存這會導致推理延遲暴增 10 倍以上系統迅速陷入癱瘓?;谖锢盹@存與 TTFT 的容量估算公式在大模型后端底座設計中不能盲目相信“高并發支持 10,000 QPS”的宣傳。應根據 GPU 顯存大小精確計算當前集群的最大并發推理 Slot 數量$$\text{MaxConcurrentSlots} \frac{\text{TotalVRAM} - \text{ModelWeightsVRAM} - \text{ActivationVRAM}}{\text{AvgContextLen} \times \text{KVCacheSizePerToken}}$$假設使用一張 80GB 顯存的 A100 GPU 運行 32B 模型模型權重占用約 64GB 顯存。激活值與系統保留占用 6GB 顯存。剩余可用于 KV Cache 的顯存為80GB - 64GB - 6GB 10GB。若平均上下文長度為 4096 Token每個 Token 消耗 KV Cache 約 1MB 顯存則單請求消耗4GB顯存。結論單張 A100 在此配置下并發支持的上下文 Slot 極限只有 2 到 3 個。超過 3 個并發應依賴 Tensor Parallelism多卡并行或者前端 Gateway 的嚴格隊列攔截。第二個關鍵指標是首字延遲TTFT。大模型推理分為 Prefill 階段計算 Prompt和 Decode 階段逐字生成。Prefill 是 Compute-bound計算密集型如果多個大 Prompt 同時進入 PrefillGPU 會發生嚴重的算力搶占導致首字遲遲無法吐出。應設定硬性 SLA 目標如P99 TTFT ≤ 1500ms。一旦當前隊列估算的 Prefill 時間超過 1.5 秒后續請求應在 Gateway 處強行截斷。多級背壓控制器實現代碼為了守護 GPU 不被 OOM 沖垮同時保證 VIP 業務不中斷后端底座應在 LLM 引擎上游構建多級信號量限流與自適應背壓控制器package gateway import ( context errors net/http sync/atomic time ) var ( ErrQueueFull errors.New(llm backend inference queue full, load shed active) ) type PriorityLevel int const ( PriorityNormal PriorityLevel iota PriorityVIP ) type LLMBackpressureController struct { maxActiveSlots int64 activeSlots int64 maxQueueLen int64 currentQueue int64 } func NewLLMBackpressureController(maxSlots, maxQueue int64) *LLMBackpressureController { return LLMBackpressureController{ maxActiveSlots: maxSlots, maxQueueLen: maxQueue, } } func (c *LLMBackpressureController) AcquireSlot(ctx context.Context, priority PriorityLevel) (func(), error) { // 1. 判斷當前活躍推理解析 Slot 是否足夠 if atomic.LoadInt64(c.activeSlots) c.maxActiveSlots { atomic.AddInt64(c.activeSlots, 1) return func() { atomic.AddInt64(c.activeSlots, -1) }, nil } // 2. Slot 滿進入背壓排隊邏輯 // 如果是普通請求且隊列已經超過 8無直接快速拒絕Fast-Fail queueLen : atomic.LoadInt64(c.currentQueue) if priority PriorityNormal queueLen int64(float64(c.maxQueueLen)*0.8) { return nil, ErrQueueFull } if queueLen c.maxQueueLen { return nil, ErrQueueFull } atomic.AddInt64(c.currentQueue, 1) defer atomic.AddInt64(c.currentQueue, -1) // 3. 在 Queue 中等待超時或可用 Slot ticker : time.NewTicker(20 * time.Millisecond) defer ticker.Stop() for { select { case -ctx.Done(): return nil, ctx.Err() case -ticker.C: if atomic.LoadInt64(c.activeSlots) c.maxActiveSlots { atomic.AddInt64(c.activeSlots, 1) return func() { atomic.AddInt64(c.activeSlots, -1) }, nil } } } } func (c *LLMBackpressureController) HTTPMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { priority : PriorityNormal if r.Header.Get(X-User-Tier) VIP { priority PriorityVIP } // 最長等待 3 秒首字排隊超時 ctx, cancel : context.WithTimeout(r.Context(), 3*time.Second) defer cancel() release, err : c.AcquireSlot(ctx, priority) if err ! nil { w.Header().Set(Retry-After, 2) w.WriteHeader(http.StatusTooManyRequests) _, _ w.Write([]byte({error: LLM Capacity Exceeded, code: 429})) return } defer release() next.ServeHTTP(w, r.WithContext(ctx)) }) }流式斷連與 Prefill 算力回收機制除了防范入站流量過載大模型后端底座還應處理**客戶端中途取消連接Client Disconnect**的算力浪費問題。在 SSE 模式下用戶看到吐出前 5 個字不符合預期經常會直接關閉網頁或點擊“停止生成”。如果 Gateway 沒有將 TCP 顯式斷開事件透傳給底層推理 EnginevLLM Engine 還會繼續傻傻地把剩下的 2000 個 Token 吐完白白浪費巨量的 GPU 顯存與計算時間。后端底座應建立Client Cancel Context Propagation機制當 Gateway 檢測到r.Context().Done()觸發Client 斷開時立即通過 gRPC / HTTP 向 vLLM 的/cancel接口發送request_id強行終止該 Request 的 Decode 循環瞬間釋放其占用的 KV Cache 頁。生產落地的底線要求在大模型應用后端底座上線前架構團隊應守住三條底線盡量禁止無限制的 HTTP 長連接排隊Gateway 層面的 Queue 長度應是有界上限超過界限立刻返回429降級提示。區分 Prefill 節點與 Decode 節點PD 分離架構高并發場景下將 Prefill計算 Prompt與 Decode生成 Token部署在不同的 GPU 節點上避免大 Prompt 輸入卡死小生成的 Token 吐出。熔斷搶占 Swap 機制一旦發現 GPU 顯存 Swap 到 CPU 內存的頻率大于 0說明系統已經嚴重超載背壓控制器應立刻提高 Load Shedding 拋棄比例。守住了 KV Cache 顯存與首字延遲這條線大模型后端底座才能在應對突發流量洪峰時做到較穩定。