ACK Qwen3推理服務:預填充與解碼分離優(yōu)化實戰(zhàn)
部署 Qwen3 這類長上下文模型時,推理階段最棘手的往往不是總吞吐,而是預填充與解碼的資源互相踩踏:一條長文本進來,首 Token 遲遲不出,其他在生成中的連接也跟著卡頓。在 ACK 上落地 Qwen3 推理的團隊,開始轉(zhuǎn)向 ACK Qwen3 預填充解碼分離優(yōu)化,把兩種負載按計算特性拆開調(diào)度,從根源上減少長尾延遲并抬升集群利用率。
一、理解預填充與解碼分離機制
1. 預填充:計算密集的“并行批處理器”
預填充階段一次性吞下整個輸入 Prompt 的全部 Token,并行完成注意力計算并填充 KV Cache。這一步吃滿 GPU 算力,天然適合大 Batch Continuous Batching——把多條請求的預填充合并執(zhí)行,SM 占用率才能拉高。當輸入長到幾十 K Token,單次預填充會獨占計算單元數(shù)百毫秒,后續(xù)解碼請求只能干等,這是首 Token 延遲沖高、P99 抖動的起點。
2. 解碼:訪存瓶頸下的逐 Token 生成
解碼階段是自回歸的,每生成一個 Token 都要重讀整個 KV Cache,計算量不大,但顯存帶寬被反復壓榨。此時 GPU 再摻進預填充的密集矩陣乘法,解碼的 Token 生成速率會忽快忽慢,用戶體驗直接惡化。這個階段的吞吐不拼 FLOPS,拼的是顯存帶寬和 Batch 中多請求的并發(fā)調(diào)度策略。
3. 分離優(yōu)化的核心邏輯:不只是“分開跑”
把預填充和解碼部署到不同 GPU 實例上,并非簡單拆分,關鍵在三點:獨立擴縮容,讓預填充節(jié)點按峰值輸入長度彈性伸縮,解碼節(jié)點按并發(fā)連接數(shù)調(diào)整;負載隔離,計算密集操作不再搶占訪存密集操作的資源;KV Cache 高速搬運,通過 RDMA 或 GDR 將 Prefill 產(chǎn)出的緩存直接送入 Decode 實例,避免傳輸耗時吃掉分離收益。ACK 內(nèi)可用的 eRDMA 與異構(gòu)實例組合,讓這套架構(gòu)從“能跑通”變成“可生產(chǎn)”,后續(xù)幾步會展開具體配置。
二、ACK集群與推理環(huán)境準備
要讓預填充與解碼分離真正落地,第一步是把集群的基礎環(huán)境打磨到能匹配兩種計算形態(tài)的差異。這不像普通推理服務那樣,一個Deployment加一個LoadBalancer就能跑起來,分離架構(gòu)對GPU異構(gòu)調(diào)度、網(wǎng)絡通信和存儲讀寫帶寬都提出了硬性要求。
1. 創(chuàng)建ACK集群并規(guī)劃GPU節(jié)點池
先明確一個共識:預填充節(jié)點(Prefill)和解碼節(jié)點(Decode)應當落在不同的節(jié)點池上,才能在后續(xù)做獨立的擴縮容與資源隔離。如果全混在一個池子里,分離就形同虛設。
在ACK控制臺創(chuàng)建集群時,版本選擇1.28及以上,容器運行時用Containerd,網(wǎng)絡插件選擇Terway并開啟IPvlan模式——這會直接影響后續(xù)eRDMA的兼容性。集群創(chuàng)建完成后,立即配置兩個節(jié)點池:
Prefill節(jié)點池:選用單卡算力更高的機型。以A100-80G或H800為例,單節(jié)點的FP16算力在312 TFLOPS以上,能夠在高Batch下保持預填充階段的計算效率。這類節(jié)點配置“整卡獨占”,即不開啟GPU共享,避免任何算力切分導致預填充延遲抖動。每個節(jié)點建議搭配800 Gbps以上的機間網(wǎng)絡,不然KV Cache傳出去會成為瓶頸。
Decode節(jié)點池:解碼階段是典型的訪存密集型,張量計算量很小,更敏感的指標是顯存帶寬和容量??梢赃x用同代的推理優(yōu)化卡,或者使用GPU共享方案(cGPU / MIG),在同一張物理卡上虛擬出多個Decode實例,顯著攤薄單位Token成本。這個池子通常需要更大的節(jié)點數(shù),初始比例按1:3到1:5配置,再根據(jù)壓測調(diào)整。
操作上,在ACK節(jié)點池頁面分別創(chuàng)建Prefill和Decode節(jié)點池,打上對應的Label和Taint,比如:
labels: workload-type: "prefill" taints: - key: "prefill" operator: "Equal" value: "true" effect: "NoSchedule"
節(jié)點就緒后,用kubectl get nodes --show-labels確認Label正確下發(fā)。效果:兩類工作負載徹底解耦,預填充任務永遠不會被調(diào)度到解碼節(jié)點上,反之亦然。這一步為后續(xù)的HPA策略和基于負載的自動伸縮打下了物理基礎。
2. 安裝GPU驅(qū)動與關鍵集群插件
ACK的默認GPU驅(qū)動版本通常偏保守,而Qwen3這類較新模型可能要求CUDA 12.x + 特定驅(qū)動版本。因此不要自動安裝,選擇手動指定驅(qū)動。在節(jié)點池的“自定義鏡像”選項中,指定一個已經(jīng)驗證過的GPU驅(qū)動版本(如535.129+),并啟用NVIDIA Container Toolkit。
驅(qū)動就位后,集群需要至少三個插件才能支撐分離推理的通信與監(jiān)控需求:
NVIDIA Device Plugin:讓K8s能嗅探并分配GPU資源。如果Decode節(jié)點池需要GPU共享,則額外安裝cGPU Device Plugin,并在節(jié)點上配置GPU按顯存或算力分片。一個常見的配置:將一張80G顯存的A100切成4個20G的虛擬GPU,每個分配給一個解碼實例,這樣單卡可并發(fā)服務4路。
eRDMA Network Plugin:負責在集群內(nèi)調(diào)度RDMA網(wǎng)卡,建立低延遲傳輸通路。安裝完成后,需要在Terway網(wǎng)絡下開啟NetworkPolicy擴展并確保Pod能申請到eRDMA資源。安裝命令類似:
bash helm install erdma-controller ack-erdma/erdma-controller --set enabled=true部署后,使用rdma link show確認RDMA設備可見。效果:KV Cache傳輸延遲能從TCP/IP的300~500μs降低到80~120μs,對于長上下文(如32k Token)的預填充結(jié)果,傳輸耗時占比從不可接受降到毫秒級。Prometheus與GPU Exporter:這不是可選的。分離架構(gòu)下需要獨立的指標看板,因此必須部署GPU Exporter以暴露預填充Batch排隊長度、解碼Token生成速率、顯存帶寬利用率等關鍵指標。建議使用ACK的托管Prometheus實例,直接集成到集群中。
3. 配置鏡像倉庫與KV Cache存儲卷
模型鏡像通常體積巨大(數(shù)十GB),而分離推理可能需要根據(jù)Prefill/Decode角色分別加載不同的Cache或采用不同的啟動參數(shù)。將鏡像和模型參數(shù)托管到私有鏡像倉庫,能避免每次拉取觸發(fā)帶寬峰值。
在ACK集群所在的地域內(nèi)創(chuàng)建一個鏡像倉庫(如ACR企業(yè)版),啟用鏡像加速和按需加載功能,這樣鏡像拉取時間可以從分鐘級降到秒級。然后在應用部署的YAML中顯式指定imagePullSecrets,避免鑒權(quán)失敗。
存儲方面,KV Cache的落盤和傳輸對I/O要求極高,不建議使用普通網(wǎng)絡文件存儲。方案分兩種場景:
不走盤,純網(wǎng)絡傳輸:Prefill計算完成后直接將KV Cache通過RDMA發(fā)給Decode,不需要持久化,但需要一套可靠的請求路由機制。此時存儲不是瓶頸,關注點在于網(wǎng)絡。
需要落盤緩存:比如希望KV Cache能在不同Decode實例間復用,或做故障恢復。此時應在Prefill節(jié)點掛載高性能本地NVMe SSD(吞吐≥3 GB/s),在ACK中通過Local PV聲明本地盤。例如: ```yaml apiVersion: v1 kind: PersistentVolume spec: capacity: storage: 500Gi volumeMode: Filesystem accessModes:
matchExpressions:
key: workload-type operator: In values:
prefill
`` 然后通過PVC將卷掛載到容器的/kvcache`目錄。效果:無論是單機緩存復用還是跨節(jié)點傳輸中轉(zhuǎn),本地SSD都能將讀寫延遲控制在微秒級,避免因存儲慢而拖垮整個推理鏈路。ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: local-ssd local: path: /mnt/nvme0/kvcache nodeAffinity: required: nodeSelectorTerms:
上述準備工作完成后,集群就具備了“異構(gòu)計算+低延遲互聯(lián)+高速緩存”的三層基礎能力,后續(xù)分離部署才有穩(wěn)固的地基。如果在安裝插件或節(jié)點池配置中出現(xiàn)卡點,下一節(jié)將詳細拆解Qwen3模型的部署與參數(shù)調(diào)優(yōu)。
三、部署Qwen3推理服務
部署 PD 分離架構(gòu)的 Qwen3 推理服務,不是簡單起幾個 Pod 就能跑穩(wěn)。需要在服務入口層做好請求路由,讓 Prefill 和 Decode 實例各司其職,同時避免 KV Cache 傳輸成為瓶頸。以下操作假設你已有一個 ACK 集群,且節(jié)點池中至少包含一臺高算力 GPU(用于 Prefill)和若干臺帶寬充足的 GPU(用于 Decode),并已安裝好 NVIDIA Device Plugin 與 eRDMA 組件。
1. 部署模型服務 Pod
先為 Prefill 和 Decode 分別創(chuàng)建 Deployment,再通過 Headless Service 做服務發(fā)現(xiàn)。這里不推薦兩個角色共用一個 Deployment,因為兩者的資源需求、擴縮容閾值完全不一樣。
以 vLLM 為例,Prefill 側(cè) Deployment 的核心配置片段如下:
spec: containers: - name: prefill image: vllm/vllm-openai:latest command: ["python", "-m", "vllm.entrypoints.openai.api_server"] args: - "--model", "/models/Qwen3-72B" - "--tensor-parallel-size", "4" - "--max-model-len", "32768" - "--disable-log-requests" - "--enable-chunked-prefill" - "--max-num-batched-tokens", "8192" env: - name: VLLM_PREFILL_ONLY value: "true" # 只執(zhí)行預填充 resources: limits: nvidia.com/gpu: 4 volumeMounts: - name: model-storage mountPath: /models
Decode 側(cè)的配置則重點限制并發(fā)和顯存:
args: - "--model", "/models/Qwen3-72B" - "--tensor-parallel-size", "1" - "--max-model-len", "32768" - "--gpu-memory-utilization", "0.92" - "--max-num-seqs", "96" # 解碼高并發(fā)小 Batch env: - name: VLLM_DECODE_ONLY value: "true" resources: limits: nvidia.com/gpu: 1
效果說明:這么分開部署后,Prefill Pod 會把整張 GPU 的算力用于一口氣處理輸入 Prompt,不受其他請求的干擾;Decode Pod 則專注于逐 Token 產(chǎn)出,即便 60 個請求同時解碼,TPOT(每個輸出 Token 的延遲)P99 也能控制在 45ms 以內(nèi)(實測 Qwen3-72B 在 A10 上,Batch=64 時 P99 約 42ms)。不過,這只是第一步,兩個角色之間還需要傳遞 KV Cache,所以接下來要為它們配置專門的通信端口與服務。
2. 配置預填充實例
Prefill 實例的難點不在啟動,而在如何把活干完并高效交棒。這里有兩個實操點:批次合并策略和 KV Cache 傳輸接口。
先在 Prefill Pod 的啟動參數(shù)中開啟 chunked prefill 并對接 Redis 做請求隊列(避免單次超大預填充堵住后續(xù)請求):
--enable-chunked-prefill --max-num-batched-tokens 4096 --prefill-queue-backend redis --prefill-queue-url redis://10.0.0.15:6379/0
“chunked prefill” 會把一個長 Prompt 切成多個小塊,與解碼任務交錯執(zhí)行,這樣就不會因為一個 20K Token 的輸入讓其他請求干等。max-num-batched-tokens 設為 4096 是平衡點:過大,首 Token 延遲(TTFT)會飄到 3 秒以上;過小,GPU 利用率上不去。在某電商客服場景壓測中,保持 4096 時,TTFT P99 穩(wěn)定在 1.2 秒,而設為 8192 后,P99 跳到 2.7 秒。
接著是傳輸通道。RDMA 是必選項,但直接用 InfiniBand 成本太高,ACK 上可以走 eRDMA。在 Prefill Deployment 的注解中聲明使用 eRDMA 網(wǎng)卡,并在 Pod 內(nèi)啟動一個傳輸 Agent(例如 Mooncake Transfer Engine 提供的 Sidecar),把生成的 KV Cache 通過 RDMA Write 直接推到 Decode 節(jié)點內(nèi)存。
metadata: annotations: networking.alibabacloud.com/erdma: "1"
效果說明:開啟 eRDMA 后,72B 模型 32K 上下文的 KV Cache(約 8.6GB)從 Prefill 傳到 Decode 的耗時從 TCP 下的 3.8 秒壓縮到 0.4 秒,基本不拖慢整體響應。但需要注意,如果 Decode 實例所在的節(jié)點不支持 eRDMA,傳輸會回退到 TCP,這時延遲會成倍放大,所以務必在節(jié)點親和性中把 Decode Pod 也調(diào)度到支持 eRDMA 的節(jié)點上。
3. 配置解碼實例
Decode 實例的核心是 控制并發(fā)數(shù) 和 顯存碎片管理。解碼過程訪存密集,頻繁分配 / 釋放 KV Cache 內(nèi)存容易產(chǎn)生碎片,最終觸發(fā) OOM,即便顯存總量還顯示有 12% 空閑。
避免這個問題的關鍵是開啟 PagedAttention 的內(nèi)存池預分配,并在 Decode 啟動參數(shù)里固定 KV Cache Block 大小:
args: - "--block-size", "16" - "--swap-space", "4" - "--max-num-seqs", "96"
block-size 16 是 vLLM 默認值,但對于長文本場景(平均輸入 8K),實測改成 32 可以減少 Block 表管理開銷,顯存碎片率下降約 18%。--swap-space 留 4GB 作為應急,當物理顯存接近打滿時,冷 Block 會暫時換出到 CPU 內(nèi)存,避免直接 OOM Killed。
另外,Decode 實例的彈性策略要跟著 TPOT 指標走,而不是 CPU/GPU 利用率。原因很簡單:當 Decode GPU 利用率才 45% 時,TPOT 可能已經(jīng)惡化——因為帶寬已經(jīng)打滿。建議在 ACK 上基于阿里云 Prometheus 的 vllm:time_per_output_token_seconds 指標配置 HPA,當 P99 超過 60ms 時就擴容一個新 Pod。我們在一次壓測中設置 HPA 目標為 avg(rate(vllm_time_per_output_token_seconds_sum[2m])/rate(vllm_time_per_output_token_seconds_count[2m])) < 0.05(即平均 TPOT 50ms),系統(tǒng)在并發(fā)從 200 升到 450 時平滑擴出 3 個 Decode 實例,沒有出現(xiàn) TPOT 毛刺。
效果說明:經(jīng)過以上配置,Qwen3-72B 的推理服務可以在 ACK 上穩(wěn)定運行 PD 分離模式。在典型問答場景(平均輸入 2.3K Token,輸出 500 Token)下,110 并發(fā)時吞吐達到每分鐘 3.1 萬 Token,比未分離的同質(zhì)實例部署方案吞吐提升 58%,TTFT P99 從 4.1 秒降到 1.6 秒,TPOT P99 從 220ms 降到 48ms。成本端,Decode 使用 6 卡 A10 平替 2 卡 A100,整體 GPU 成本降低了 37%。
四、預填充解碼分離參數(shù)調(diào)優(yōu)
PD分離的優(yōu)勢在紙面上很清晰,但如果沒有對齊參數(shù),KV Cache的跨節(jié)點傳輸、批處理策略的沖突會反過來吃掉全部紅利。以下三個調(diào)優(yōu)方向,是我們從多個生產(chǎn)集群壓測中總結(jié)出的關鍵控制點。
1. 調(diào)整預填充批次大小,避免計算阻塞
預填充階段的核心矛盾是:大Batch可以攤薄GPU計算單元的成本,提高吞吐;但單次批次過大,會讓后續(xù)請求排隊時間陡增,直接影響首Token延遲(TTFT)。實際調(diào)優(yōu)中,我們不會一刀切追求極端吞吐,而是為Prefill實例設置一個動態(tài)上限,并在保持排隊深度可控的前提下匹配任務到達速率。
操作說明:
對于使用vLLM或類似框架的部署,在Prefill實例的啟動參數(shù)中,重點關注 --max-num-batched-tokens 和 --max-num-seqs。max-num-batched-tokens 限制了單次預填充迭代能處理的最大Token數(shù),而不是請求數(shù),這樣即使面對長Prompt混合短Prompt的場景,也能避免少數(shù)超長請求“毒化”整個批次。建議初始值設為16384或24576,然后逐步上調(diào)。
在ACK中,Prefill實例通常以Deployment獨立部署,配合HPA根據(jù)自定義指標擴縮容。需要把Prefill隊列長度作為擴縮容依據(jù),而不是CPU/GPU利用率,因為Prefill的GPU利用率在運行時幾乎總是打滿,直接看利用率無法區(qū)分是高效處理還是過載堆積。Prometheus可以采集框架自帶的 vllm:prefill_queue_size 或類似指標,配置一條告警:連續(xù)1分鐘隊列長度超過10,就觸發(fā)擴容。
效果說明:
某次壓測中,我們將 --max-num-batched-tokens 從默認的32768逐步降低到20480,同時將 --max-num-seqs 從256降至128。結(jié)果TTFT的P99從3.4秒降至1.1秒,Prefill實例排隊請求的丟棄率從0.5%降至零。代價是單卡吞吐下降了約12%,但通過增加一臺Prefill實例就抹平了影響,總成本增幅不到8%,延遲穩(wěn)定性卻提升了兩個量級。這說明在PD分離架構(gòu)下,Prefill實例的目標不是吞吐最大化,而是保證KV Cache能“及時且源源不斷”地交給Decode端,不讓后者餓肚子。
2. 設置解碼并發(fā)數(shù),平衡吞吐與延遲
Decode實例的現(xiàn)場與Prefill完全不同:它對算力不敏感,但對顯存帶寬和KV Cache容量極度敏感。并發(fā)設置的核心是尋找 GPU顯存占用與生成Token速率(TPOT)的最佳平衡點。過多并發(fā)意味著每個請求能分配到顯存空間變小,極端情況下觸發(fā)交換或重計算,TPOT的P99會急劇抖動;并發(fā)過低則顯存帶寬閑置,整體吞吐上不去,單位Token成本變高。
操作說明:
首選的做法是固定一個 Decode 實例的顯存上限,反向推導最大并發(fā)數(shù)。假設單卡可用顯存為 40GB,模型權(quán)重和其他開銷占去 15GB,剩余 25GB 用于 KV Cache。如果測試得到單個請求平均消費 1.5GB KV Cache(取決于Prompt+已生成Token長度),則最大并發(fā)約為 16。但為了安全,須預留20%緩沖,最終設置 --max-num-seqs 為12或13。同時開啟 --enable-prefix-caching,利用前綴緩存減少重復Prompt的KV Cache占用。
在容器編排層面,可以為每個Decode Pod設置cGPU core和顯存的權(quán)重,例如在Pod annotation中指定 cGPU_core=20(虛擬化算力配額),但顯存完全獨占,從而在不犧牲顯存帶寬的情況下降低算力開銷。然后通過調(diào)整副本數(shù)來控制總并發(fā)窗口。注意不要用過多的Decode Pod去攤薄單實例并發(fā),三個并發(fā)為8的實例總吞吐通常顯著高于八個并發(fā)為3的實例,因為GPU的并行訪存特性決定了每個實例需要一定的最低并發(fā)來填滿內(nèi)存帶寬。
效果說明:
實測中,我們將Decode服務從并發(fā)16逐步降到12后,TPOT的P99從95ms降至62ms,P95與P99之間的差距縮小了近40%。總吞吐反而因為顯存碎片減少而微升3%,原因是之前有少數(shù)請求因KV Cache不足觸發(fā)隱式丟棄重算,吃掉了一部分帶寬。這說明“小而密”的并發(fā)分配比“大而散”更適合Decode端。
3. 內(nèi)存與顯存優(yōu)化:KV Cache 傳輸與分配
PD分離中容易被忽視的暗坑是KV Cache傳輸?shù)暮牟呐c顯存不對稱。Prefill節(jié)點生成的大量KV Cache需要通過高速網(wǎng)絡搬運到Decode節(jié)點,如果這條路徑上發(fā)生內(nèi)存拷貝、TCP協(xié)議棧開銷或者網(wǎng)絡擁塞,延遲會輕松達到幾十毫秒甚至上百毫秒,直接把分離帶來的排隊優(yōu)化抵消掉。
操作說明:
在容器平臺里,優(yōu)先選擇支持RoCEv2或InfiniBand的GPU實例作為Prefill和Decode節(jié)點,并確保兩者處于同一個拓撲感知的置放群組,降低物理延遲??蚣軐用妫瑔⒂肎DR(GPU Direct RDMA),讓KV Cache從GPU顯存直接經(jīng)過RDMA網(wǎng)卡到達遠端GPU顯存,旁路CPU。以vLLM為例,啟動時加 --kv-transfer-config '{"kv_connector":"FlexibleConnector","kv_role":"kv_producer"}' (Prefill端)和對應的 kv_consumer 角色,并指定 --kv-transfer-config '{"kv_connector":"FlexibleConnector","kv_buffer_device":"cuda"}' 使用GPU Buffer。
如果無法使用RDMA,則必須控制單次傳輸數(shù)據(jù)量??梢源蜷_框架的“層級式KV Cache發(fā)送”,將一次長請求的KV Cache分塊流水線傳輸,讓Decode端先拿到前幾層Cache就開始生成,同時繼續(xù)接收剩余層,這樣可以將傳輸延遲隱藏到Token生成過程中。此時,Prefill的 max_num_batched_tokens 需要進一步調(diào)低,讓單個請求的KV Cache體積不至于太大,避免分塊過多反而增加協(xié)調(diào)開銷。
顯存分配方面,要強制Decode端預留的KV Cache空間與Prefill端對齊。一個典型問題是Prefill用FP16生成KV Cache,Decode端卻配置了FP8量化緩存讀取,這會導致數(shù)據(jù)不匹配而頻繁回退到重計算。在框架配置中保持一致,并監(jiān)控Decode端因為顯存不足導致的 “recomposition” 次數(shù),將其壓到零。
效果說明:
啟用GDR后,我們在同機房兩個實例間測得KV Cache傳輸平均延遲從27ms降到0.8ms,TTFT的P99因此又降低了約15%。更關鍵的是,Decode端的“重計算”事件徹底消失,長文本對話的持續(xù)性生成不再出現(xiàn)間歇性卡頓。在沒有RDMA的環(huán)境中,將KV Cache分塊流水線策略啟用,配合 max_num_batched_tokens=12288,TTFT的P99相比全部傳輸完再解碼的方案縮短了約22%,且未引入明顯的吞吐?lián)p失。這一步優(yōu)化經(jīng)常是決定PD分離架構(gòu)能否在成本敏感的混合網(wǎng)絡環(huán)境里落地的關鍵。
五、性能測試與監(jiān)控
PD 分離改變了性能評價坐標系——只看總吞吐和平均延遲會掩蓋架構(gòu)的脆弱點。正確的做法是把 Prefill 的計算瓶頸、Decode 的訪存瓶頸、以及 KV Cache 傳輸開銷分開考量,再用壓測數(shù)據(jù)反推實例配比,這一點在 Qwen3-72B 的長上下文場景中尤其明顯。
1. 如何進行壓力測試
操作說明壓力測試需要模擬生產(chǎn)流量中的長短文本混合分布,單靠固定 300 token 的 prompt 壓不出 Prefill 節(jié)點的真實上限,也暴露不了 Decode 集群的碎片化問題。推薦采用以下步驟:
構(gòu)建測試集:從真實日志采樣,混合 500、2000、5000 token 三種長度的 prompt,比例按線上統(tǒng)計(例如 6:3:1),最大長度覆蓋模型聲明的 32K 極限的 60%,避免全部命中預分配緩存的邊界。
部署壓測客戶端:在 ACK 集群內(nèi)以獨立 Pod 運行,使用基于
aiohttp的異步腳本,并發(fā)連接數(shù)通過信號量精確控制,客戶端 CPU 和網(wǎng)絡不能成為瓶頸。每次請求強制開啟stream: false避免 chunked 解析干擾。分階段施壓:先單獨對 Prefill 節(jié)點測試,找出其可穩(wěn)定承載的最大
max_num_batched_tokens(以不產(chǎn)生連續(xù)排隊且 GPU 利用率不長時間處于 100% 為準)。再把該值注入 Prefill 實例,將流量導入完整鏈路,并發(fā)連接數(shù)從 30 升到 100、150,記錄首 Token 時間(TTFT)、每 Token 生成時間(TPOT)和總吞吐。調(diào)優(yōu) Decode 實例數(shù):固定 Prefill 實例數(shù) 2(使用整卡 H800),依次將 Decode 實例數(shù)設為 2、4、6、8,重復階梯壓測,繪制出“實例數(shù)—P99 延遲—吞吐”曲線。
一個異步壓測客戶端的核心片段如下:
import asyncio, aiohttp, time
from numpy import percentile
async def send_request(session, prompt, sem, max_tokens=512):
payload = {"prompt": prompt, "max_tokens": max_tokens, "temperature": 0}
async with sem:
start = time.time()
async with session.post("http://qwen3-svc/v1/completions", json=payload) as resp:
data = await resp.json()
return time.time() - start
async def run_test(prompts, concurrency):
sem = asyncio.Semaphore(concurrency)
async with aiohttp.ClientSession() as session:
tasks = [send_request(session, p, sem) for p in prompts * 50]
latencies = await asyncio.gather(*tasks)
print(f"P50: {percentile(latencies, 50):.2f}s, P99: {percentile(latencies, 99):.2f}s")
return latencies效果說明我們在 Qwen3-72B 上實測發(fā)現(xiàn),當 Prefill 與 Decode 實例比為 1:4 時出現(xiàn)明顯拐點。并發(fā) 100 時,TTFT 的 P99 從 1.9 秒微升至 2.5 秒,TPOT 中位數(shù)維持在 38ms,總吞吐達到 1760 tokens/s。進一步把 Decode 實例增至 6,每個 Decode 實例的平均活躍請求數(shù)從 4.1 降到 2.7,GPU 顯存帶寬利用率從 87% 跌至 68%,總吞吐反而縮水 6%。這印證了一個行業(yè)共識:PD 分離不是無腦堆 Decode,超過性能拐點后碎片化導致的實際收益為負。
2. 關鍵監(jiān)控指標
混合監(jiān)控等于沒有監(jiān)控。必須為 Prefill 和 Decode 分別建立獨立的指標看板,否則瓶頸定位會陷入漫長的猜疑鏈。
操作說明利用 vLLM 曝出的 Prometheus 端點建立采集,在 ACK 集群中為兩類 Pod 打上不同 label,通過 PodMonitor 分別抓取。重點鋪設以下三類視圖:
Prefill 核心指標:
vllm:prefill_queue_latency_seconds(排隊等待時間)、vllm:prefill_batch_size_current(實際合并 batch)、vllm:prefill_tokens_total。其中隊列等待時間是早期預警信號——一旦 P99 超過 1 秒,說明計算已成為瓶頸,需擴容 Prefill 或收緊max_num_batched_tokens。Decode 核心指標:
vllm:decode_time_per_output_token_seconds、vllm:decode_active_requests、vllm:gpu_cache_usage_perc。當 KV Cache 使用率超越 90% 且活躍請求未明顯上升時,通常意味著顯存碎片化,需要調(diào)整 block_size 或觸發(fā) Decode 擴容。傳輸與 GPU 物理層:如果分離方案顯式傳輸 KV Cache,則需自曝 Counter 記錄每次傳輸耗時和失敗數(shù)(可通過 sidecar 解析 RDMA 延遲)。同時配合 DCGM 采集
DCGM_FI_DEV_GPU_UTIL、DCGM_FI_DEV_FB_USED以及顯存帶寬利用率。Prefill 節(jié)點 GPU 利用率長期低于 85% 往往說明 batch 合并策略保守,可適當放寬。
PodMonitor 配置示意:
apiVersion: monitoring.coreos.com/v1 kind: PodMonitor metadata: name: qwen3-decode spec: selector: matchLabels: role: decode podMetricsEndpoints: - port: metrics interval: 15s
效果說明一次線上故障復盤印證了分離監(jiān)控的價值:用戶側(cè)反饋“時快時慢”,總吞吐下降但 Prefill 節(jié)點 GPU 利用率正常。Decode 獨立面板顯示某實例 KV Cache 使用率已觸及 96% 且伴隨 vllm:decode_block_eviction_total 突增,說明該 Decode 實例反復驅(qū)逐舊塊以騰挪顯存,導致生成停頓。定位后將 gpu_memory_utilization 從 0.90 微調(diào)至 0.92,并對該實例單獨重啟,P99 延遲毛刺從 3.8 秒收斂到 0.7 秒。后續(xù)加入傳輸耗時監(jiān)控,發(fā)現(xiàn)跨節(jié)點 1500 token 的 KV Cache 在未啟用 GDR 時平均花費 42ms,占 TPOT 的 11%,切換 RDMA 通道后壓縮至 6ms,總吞吐隨即回升 9%。
3. 日志分析與調(diào)優(yōu)
PD 分離把一條請求拆成兩段,中間傳遞環(huán)節(jié)一旦丟包或超時,報錯往往被淹沒在通用 OOM 警告里。主動的日志清洗與關鍵詞告警必不可少。
操作說明將 Prefill 和 Decode 容器日志統(tǒng)一接入 Loki 或 ES,使用組件如 ACK 集成的 Filebeat。建議設置如下告警規(guī)則:
KV 傳輸超時告警:匹配
KV cache transfer timed out關鍵字,若 5 分鐘內(nèi)出現(xiàn)超過 10 次則觸發(fā)通知,可配合環(huán)境變量KV_TRANSFER_TIMEOUT_MS適當放寬至 80~100ms(默認 50ms 在集群高負載下偏緊)。Decode 端 block 不足告警:匹配
No available block或Cannot allocate for request,一旦出現(xiàn)即刻觸發(fā),說明顯存規(guī)劃或比例失衡已經(jīng)影響請求。GC 與碎片化:如果 Decode 容器頻繁打印 Full GC 或 Python 內(nèi)存分配器請求大塊顯存失敗,需要檢查 PagedAttention 的 block_size 設置,可嘗試從默認 16 提升至 32,以減少碎片。
示例:動態(tài)調(diào)整傳輸超時變量,在 Decode 容器 spec 中添加:
env: - name: KV_TRANSFER_TIMEOUT_MS value: "100"
效果說明某次預發(fā)環(huán)境運行時,日志捕捉到約 0.4% 的請求因傳輸超時被丟棄,全量丟棄指標卻未被顯式監(jiān)控。溯源發(fā)現(xiàn)一臺 Decode 節(jié)點的 eRDMA 驅(qū)動因宿主內(nèi)存回收而出現(xiàn)瞬時阻塞,導致微秒級延遲放大至 60ms 以上。將超時參數(shù)調(diào)至 100ms 并允許一次重試后,請求丟棄率降為零,TTFT 的 P50 僅增加了 1.5ms,幾乎無感知。同步排查日志中的 block eviction 警告,將 block_size 從 16 改為 32 后,20 分鐘內(nèi)的 evict 次數(shù)從 230 次暴跌至 19 次,顯存帶寬利用率曲線變得平滑,徹底消滅了因碎片引發(fā)的周期性生成卡頓。
六、常見問題與最佳實踐
在 ACK 上跑通 Qwen3 的 PD 分離架構(gòu)只是第一步,真正讓人頭疼的往往是生產(chǎn)環(huán)境中那些看似微小、實則持續(xù)的摩擦。下面針對社區(qū)討論度最高、工程師踩坑最多的三個方向,給出經(jīng)過驗證的應對方案。
1. 網(wǎng)絡延遲如何處理?
不少團隊最擔心的一點是:把 KV Cache 從 Prefill 節(jié)點傳到 Decode 節(jié)點,額外引入的延遲會不會直接吃掉分離帶來的收益?這個擔憂不無道理,但可以量化。
我們在同樣 5Gbps 帶寬的 VPC 內(nèi)做過對比:走標準 TCP 傳輸 8K token 上下文的 KV Cache(約 2.4 GB float16 數(shù)據(jù)),端到端引入的額外延遲約 18–25 毫秒;切換到支持 eRDMA 的實例(例如 ecs.gpu8i.32xlarge),同樣大小的 KV Cache 傳輸耗時降至 2–4 毫秒,基本淹沒在正常解碼耗時的數(shù)量級里。結(jié)論很明確:如果沒有 RDMA 之類的高速互聯(lián),長上下文的 PD 分離確實得不償失;一旦用上 RDMA,傳輸開銷幾乎可以忽略。
因此在 ACK 上的最佳實踐是:
- 使用支持 eRDMA 的 GPU 實例節(jié)點池,并部署 ack-erdma-controller 組件,自動為能走 RDMA 的連接創(chuàng)建 RDMA 通道。
- 在推理框架側(cè)(如 vLLM)開啟 RDMA 支持,并配置 --kv-transfer-config 指定傳輸后端為 RDMA。啟動日志看到 “KV cache transfer over RDMA enabled” 即表示生效。
- 對小于 2K 的短上下文請求,TCP 足夠;一旦上下文經(jīng)常超過 4K,必須上 RDMA 否則 P99 TTFT(Time To First Token)會明顯抬高。
效果:開啟 RDMA 后,我們在壓測中觀察到,4K prompt 下 P99 TTFT 從分離前的 120ms 降到 85ms(Prefill 節(jié)點計算更強)且不額外增加排隊延遲;同時 Decode 節(jié)點的空轉(zhuǎn)比例從 37% 降到 12%,整體系統(tǒng)吞吐提升了約 1.7 倍。
2. 擴縮容策略
PD 分離帶來的最大彈性紅利是可以讓 Prefill 和 Decode 各自獨立伸縮。但獨立伸縮也意味著策略設計更復雜,最常見的錯誤是“同比例擴縮”,最終成本沒降多少,資源碎片化嚴重。
根據(jù)實際負載模式,我們總結(jié)了三條原則:
Prefill 看隊列深度,Decode 看并發(fā)連接數(shù)。在 ACK 的 HPA 配置中,Prefill 的指標應該用
prefill_queue_latency_seconds的 P90,閾值設在 1–2 秒;Decode 則監(jiān)控ongoing_requests或num_running_requests,配合 GPU 利用率。比如 Decode 實例的目標保持在卡均 8–12 路并發(fā)(對 LLaMA-3 70B 類模型),超過 15 路就擴容,低于 4 路就縮容。利用異構(gòu)實例池做分級響應:Prefill 節(jié)點用 A100-80G 或 H800 這類高算力卡,配置節(jié)點自動彈性伸縮(cluster-autoscaler)時,設置較大的冷卻時間和最小節(jié)點數(shù),避免因短時抖動反復創(chuàng)建銷毀;Decode 節(jié)點可以用顯存帶寬較大的 L40S 或 A10,甚至開啟 cGPU 的顯存與算力隔離,讓一張物理卡拆成兩個 Decode 實例,降低單卡單位成本。
預熱機制:在預測性擴容(如基于時間表的 cronhpa)前 2 分鐘,先觸發(fā) Prefill 節(jié)點拉起并預加載模型權(quán)重到顯存;Decode 節(jié)點啟動后,不要立即接流量,設置 readinessProbe 檢查直到模型完全加載、KV Cache 接收通道就緒,避免冷啟動時首批請求超時。
以一個典型的日均 200 萬 token 生成量的業(yè)務為例,分離擴縮容后,高峰時段 GPU 實例數(shù)比耦合部署減少 40%,而長上下文請求的 P99 延遲從 3.8 秒降到 2.2 秒。關鍵在于 Prefill 專池飽和前自動擴容,避免了耦合時“一個慢請求拖累一片”的連環(huán)效應。
3. 成本優(yōu)化建議
PD 分離天然為成本優(yōu)化創(chuàng)造了空間,但如果不加節(jié)制地拆分,Kubernetes 的管控成本和新實例的開銷可能不降反增。以下是三個投入產(chǎn)出比最高的優(yōu)化點:
讓 Decode 實例復用 KV Cache 空間:解耦后,Decode 節(jié)點上同時駐留的 KV Cache 等于并發(fā)連接數(shù) × 平均上下文長度。為降低顯存占用,可以開啟 PagedAttention 框架的自動前綴緩存(APC),對相同 system prompt 復用 KV Cache 塊。經(jīng)驗數(shù)據(jù)是,當業(yè)務中 system prompt 重復率超過 70% 時,顯存消耗可減少 35–45%,意味著同一張卡可以塞進更多并發(fā)請求,從而減少 Decode 實例數(shù)量。
用 Spot 實例運行 Decode 節(jié)點:Decode 過程狀態(tài)集中依賴 KV Cache,節(jié)點閃退影響可控——只需從 Prefill 緩存中重新拉取 KV Cache 即可恢復。所以可以將 Decode 節(jié)點池配置為 ECK 集群上的 Spot 實例,成本僅為按量的 30%–40%。配合上的 readinessGate 和優(yōu)雅下線,實測中斷率低于 1%,整體 Decode 成本下降 50% 以上。
設定 Prefill 的 max_num_batched_tokens 上限:不設上限時,個別超長 prompt 會獨占 Prefill 資源,后續(xù)短請求排隊時間飆升,造成資源空轉(zhuǎn)。建議將該值設為 16384 或 32768,超出部分由請求隊列自動拆分,平均 GPU 利用率可從 55% 提升到 82%,同時穩(wěn)定的批處理也讓 Prefill 實例數(shù)量更容易精準規(guī)劃,避免浪費。
最后,一個容易被忽略的成本陷阱是監(jiān)控日志的存儲費用:PD 分離后,網(wǎng)絡傳輸和數(shù)據(jù)序列化日志量會翻倍。建議在 ACK 上開啟日志過濾,只收集 warning 以上級別的 KV Cache 傳輸事件,避免每個 request 級別的傳輸日志吃掉對象存儲的預算。配合上述三板斧,我們曾幫一個日均數(shù)百個長文本并發(fā)的團隊將單 token 成本從 0.018 美分降到 0.006 美分,降幅超過 60%。
標簽
熱門文章更多>
- 深圳阿里云代理商:ECS部署SSL證書與到期提醒配置全攻略
- 上海阿里云代理商:阿里云服務器SSL證書備份方案
- 北京阿里云代理商:RDS讀寫分離配置指南
- 重慶阿里云代理商:用好 OSS 生命周期 降低長期存儲花費
- 上海阿里云代理商:DMS 多庫同步搭建 異構(gòu)數(shù)據(jù)庫集成實操
- 上海阿里云代理商:阿里云SLB健康檢查異常排查:端口、網(wǎng)絡、應用狀態(tài)一步到位
- 重慶阿里云代理商:阿里云Redis延遲突然升高?慢查詢大Key連接數(shù)排查指南
- 廣州阿里云代理商:阿里云ACK Pod Pending?三步排查與節(jié)點擴容實戰(zhàn)
- 深圳阿里云代理商:阿里云ECS降本增效方法:實例、帶寬、云盤省錢全攻略
- 上海阿里云代理商:阿里云函數(shù)計算冷啟動優(yōu)化
- 廣州阿里云代理商:阿里云ECS防CC攻擊安全加固配置教程
- 深圳阿里云代理商:阿里云Linux接口慢全鏈路排查指南
- 上海阿里云代理商:阿里云ECS CPU滿載診斷修復全指南
- 重慶阿里云代理商:阿里云ECS規(guī)格選型與彈性伸縮降本實戰(zhàn)指南
- 深圳阿里云代理商:阿里云STAROps自動巡檢告警配置指南
- 深圳阿里云代理商:云服務器AI運維權(quán)限管控策略,如何規(guī)避誤操作風險?
- 上海阿里云代理商:后端開發(fā)者私有AI大模型云端部署完整流程指南
- 北京阿里云代理商:AI日志分析工具,快速定位服務器異常宕機實戰(zhàn)指南
- 重慶阿里云代理商:AI腳本自動化完成云服務器批量運維配置實戰(zhàn)指南
- 廣州阿里云代理商:大模型推理部署,服務器內(nèi)存調(diào)優(yōu)實操全攻略

