本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
HyperPod 推論的分解預填充和解碼
分解的預先填充和解碼 (DPD) 會將 LLM 推論的兩個階段預先填充和解碼分成專用 GPU 集區,並使用 GPU 直接遠端記憶體存取 (RDMA),在它們之間透過 Elastic Fabric Adapter (EFA) 傳輸金鑰值 (KV) 快取。
在相同 GPU (共置) 上執行預填充和解碼時,單一長內容請求可能會停止其他用戶端的傳輸中權杖串流,在負載下增加每個權杖的延遲。DPD 會在一組 GPUs 上執行運算限制預先填入,並在另一組 GPU 上執行memory-bandwidth-bound解碼,在混合流量下產生更可預測的延遲,並讓您獨立擴展每個階段,藉此消除此干擾。
推論運算子會處理協同運作,包括佈建路由器、透過 LMCache 和 NIXL 將 Pod 預先填充和解碼,以及與 HyperPod 可觀測性整合。您可以將pdSpec區段新增至已用於推論端點的相同InferenceEndpointConfig資源,以啟用 DPD。
當 DPD 協助
當下列所有條件都存在時,DPD 可提供最大效益:
-
大型密集模型 — 70B+ 參數 (例如 Llama 3.3 70B)。
-
長輸入 — 4,000+ 個輸入字符。輪換間延遲 (ITL) 改善會隨著輸入長度而擴展,因為在共置時,預先填充時間較長會導致更多解碼干擾。
-
持續並行 — 每秒 2 個以上的請求。如果沒有在相同 GPU 中競爭的並行請求,則無需分離。
-
中等或長輸出 — 256+ 個輸出字符。更多輸出字符表示每個字符的穩定延遲能獲得更多累積效益。
如果您的工作負載具有短輸入、低並行或使用小型模型,則標準共置部署會更簡單且效能良好。
先決條件
在部署使用分解預先填充和解碼的推論端點之前,您需要在本機開發環境中設定下列元件:
-
透過 kubectl
存取 HyperPod Amazon EKS 叢集 -
Hugging Face
權杖,允許對個別模型檢查點的讀取存取權。如果模型檢查點已位於 Amazon S3 儲存貯體中,則不需要這麼做。 -
工作者映像,其中包含 vLLM、LMCache、NVIDIA NIXL 和 EFA libfabric 供應商。支援以下影像選項:
-
DLC:
public.ecr.aws/deep-learning-containers/vllm:server-hyperpod-cuda-v1.1 -
LMCache:
lmcache/vllm-openai:v0.4.3
這兩個影像都包含 LMCache 0.4.3、vLLM 0.19.0 和 NIXL 1.0.0。
-
-
已安裝 HyperPod Inference Operator 3.2 版或更新版本。舊版不支援 DPD。根據預設,運算子會安裝在新建立的 HyperPod Amazon EKS 叢集中。如果您想要使用現有的叢集,請遵循中的安裝指示設定 HyperPod 叢集以進行模型部署。驗證您的版本:
kubectl get deployment hyperpod-inference-operator-controller-manager \ -n hyperpod-inference-system \ -o jsonpath='{.spec.template.spec.containers[?(@.name=="manager")].image}{"\n"}'
重要
分解的預先填充和解碼需要具備 EFA 功能的執行個體,並支援 GPU-Direct RDMA。支援下列執行個體類型:ml.p5.48xlarge、ml.p5e.48xlarge、ml.p5en.48xlarge、ml.p6-b200.48xlarge、ml.p6-b300.48xlarge。DPD 不支援其他執行個體類型。
部署 DPD 端點
大多數InferenceEndpointConfig欄位會與非 DPD 端點共用,並記錄在 中部署基礎模型和自訂微調模型。若要啟用 DPD,請將下列區段新增至資訊清單。
Prefill-Decode 規格: pdSpec
宣告預先填充/解碼拓撲並指定引數。此欄位的存在是造成端點分解的原因:運算子會建立個別的部署以進行預先填充和解碼,並透過路由器和 LMCache PD 後端將它們連接在一起。
pdSpec: prefillSpec: replicas: 1 resources: limits: nvidia.com/gpu: ${GPUS_PER_NODE} requests: nvidia.com/gpu: ${GPUS_PER_NODE} args: - "--gpu-memory-utilization" - "0.75" decodingSpec: replicas: 1 resources: limits: nvidia.com/gpu: ${GPUS_PER_NODE} requests: nvidia.com/gpu: ${GPUS_PER_NODE} routingThreshold: 4096
replicas-
獨立擴展預填充和解碼。
resources-
套用至角色的 Pod 規格。DPD Pod
worker.resources會忽略頂層;每個角色值覆寫。 routingThreshold-
將請求路由至分解路徑的字符長度閾值。不符合此閾值的請求會略過預填充物,並直接前往解碼器。
args-
vLLM 標記專屬於該角色。在啟動
worker.args時合併至 : 中已存在的旗標worker.args會取代為每個角色的值;未存在的旗標會附加。
DPD 環境變數: environmentVariables
這些環境變數會同時套用至預填充和解碼器容器;沒有每個角色的 env-var 欄位。對於每個角色行為,請pdSpec.{prefillSpec,decodingSpec}.args改用 。
environmentVariables: - name: PD_BUFFER_SIZE value: "8589934592" - name: LMCACHE_SAVE_DECODE_CACHE value: "False" - name: PYTHONHASHSEED value: "0"
PD_BUFFER_SIZE(8 GiB)-
解碼器上預留用於傳入 KV 快取傳輸的 GPU 緩衝區,每個排名的大小。對於 TP=8 的 Llama 70B,每個字符的 KV 快取每個排名大約 40 KB,因此每個排名大約 0.23 GB 的 6000 個字符提示,而 8 GiB 可容納大約 35 個此類傳輸中。當緩衝區超過容量時,解碼器日誌
Failed to allocate memory object, retrying...和用戶端會看到延遲峰值。decodingSpec.replicas視需要增加至 16/32 GiB 或擴展。 LMCACHE_SAVE_DECODE_CACHE:"False"-
停用解碼器上的備援 L1 快取。預填充物是快取命中事件的事實來源。
PYTHONHASHSEED:"0"-
LMCache 使用 Python 的內建
hash()來計算提示詞快取金鑰。根據預設,Python 會隨機化每個程序的雜湊種子,因此相同的提示會在預填充和解碼器和查詢遺漏時產生不同的金鑰。固定種子可讓金鑰跨 Pod 一致。
設定路由策略
intelligentRoutingSpec 區段會設定 DPD 路由器用來為每個請求選取預先填入程式的路由策略。路由器pdSpec會在存在時自動建立;本節是選用的,預設為 prefixaware。
intelligentRoutingSpec: enabled: true routingStrategy: prefixaware
DPD 也可以與智慧型路由和 KV 快取整合。如需詳細資訊,請參閱設定 KV 快取和智慧型路由。
使用單一預填充複本時,所有策略都會路由到該複本。選擇只會影響下列行為prefillSpec.replicas > 1:
-
對於單一預先填入複本,當提示共用常見字首時,請使用
prefixaware(預設值) 將 KV 快取命中最大化,例如系統提示或聊天歷史記錄。 -
對於多個預填充複本,請使用
roundrobin將負載平均分配到複本,並避免熱灌入單一預填充器。
完成範例
下列資訊清單會在兩個 ml.p5.48xlarge 執行個體 (一個預填充物、一個解碼器) 上部署 Llama 3.3 70B:
apiVersion: inference.sagemaker.aws.amazon.com/v1 kind: InferenceEndpointConfig metadata: name: dpd-test namespace: default spec: endpointName: dpd-test instanceType: ml.p5.48xlarge invocationEndpoint: v1/chat/completions modelName: Llama-3.3-70B-Instruct modelSourceConfig: modelSourceType: s3 modelLocation: Llama-3.3-70B-Instruct s3Storage: bucketName: <YOUR_BUCKET> region: <YOUR_REGION> loadBalancer: healthCheckPath: /health metrics: enabled: true kvCacheSpec: enableL1Cache: true intelligentRoutingSpec: enabled: true routingStrategy: prefixaware pdSpec: prefillSpec: replicas: 1 resources: requests: nvidia.com/gpu: "8" limits: nvidia.com/gpu: "8" decodingSpec: replicas: 1 resources: requests: nvidia.com/gpu: "8" limits: nvidia.com/gpu: "8" routingThreshold: 4096 worker: image: public.ecr.aws/deep-learning-containers/vllm:server-hyperpod-cuda-v1.1 args: - "--model" - "/opt/ml/model" - "--host" - "0.0.0.0" - "--port" - "8000" - "--tensor-parallel-size" - "8" - "--max-model-len" - "16384" - "--gpu-memory-utilization" - "0.75" modelInvocationPort: name: http containerPort: 8000 modelVolumeMount: name: model-weights mountPath: /opt/ml/model resources: requests: cpu: "96" memory: 1024Gi nvidia.com/gpu: "8" limits: cpu: "96" memory: 1024Gi nvidia.com/gpu: "8" environmentVariables: - name: HF_HOME value: /tmp/hf_home - name: PD_BUFFER_SIZE value: "8589934592" - name: LMCACHE_SAVE_DECODE_CACHE value: "False" - name: PYTHONHASHSEED value: "0"
套用資訊清單:
kubectl apply -f inference_endpoint_dpd_config.yaml
驗證部署
影像提取和模型載入需要幾分鐘的時間。監控 Pod 狀態:
kubectl get pods -A \ | grep -E "prefill-|decode-|router"
運作狀態良好的部署會顯示:
NAMESPACE NAME READY STATUS RESTARTS AGE default prefill-dpd-test-XXXX 3/3 Running 0 7m default decode-dpd-test-XXXX 3/3 Running 0 7m hyperpod-inference-system dpd-test-router-XXXX 2/2 Running 0 7m
每個模型 Pod 都有 3 個容器 (vLLM 工作者、Nginx 反向代理、OpenTelemetry 收集器)。路由器 Pod 有 2 個容器 (路由器、OpenTelemetry 收集器)。檢查InferenceEndpointConfig狀態:
kubectl get inferenceendpointconfig dpd-test -n default \ -o jsonpath='{.status.conditions[0].message}{"\n"}'
預期的輸出: DPD prefill and decode deployments are ready
驗證 DPD 角色
確認預填充物報告sender和解碼器報告 receiver。這是區分程度最高的啟動訊號 - 如果兩個 Pod 都報告相同的角色,或兩者都不列印該行,則運算子未正確連接 DPD。
PREFILL_POD=$(kubectl get pod -n ${NAMESPACE} \ -l 'inference.sagemaker.aws.amazon.com/dpd-role=prefill' \ -o jsonpath='{.items[0].metadata.name}') DECODE_POD=$(kubectl get pod -n ${NAMESPACE} \ -l 'inference.sagemaker.aws.amazon.com/dpd-role=decode' \ -o jsonpath='{.items[0].metadata.name}') kubectl logs $PREFILL_POD -n ${NAMESPACE} -c prefill-${DEPLOYMENT_NAME} \ | grep -oE "'pd_role': '[a-z]+'" | sort -u kubectl logs $DECODE_POD -n ${NAMESPACE} -c decode-${DEPLOYMENT_NAME} \ | grep -oE "'pd_role': '[a-z]+'" | sort -u
預期的輸出結果:
'pd_role': 'sender' 'pd_role': 'receiver'
調用端點
端點就緒後,傳送一小段和長段提示來練習兩個路由路徑,然後檢查日誌以確認透過 EFA 傳輸 KV。
PREFILL_POD=$(kubectl get pod -n ${NAMESPACE} \ -l 'inference.sagemaker.aws.amazon.com/dpd-role=prefill' \ -o jsonpath='{.items[0].metadata.name}') DECODE_POD=$(kubectl get pod -n ${NAMESPACE} \ -l 'inference.sagemaker.aws.amazon.com/dpd-role=decode' \ -o jsonpath='{.items[0].metadata.name}') ROUTER_POD=$(kubectl get pods -n hyperpod-inference-system -o name \ | grep -- "${DEPLOYMENT_NAME}-${NAMESPACE}-router" | head -1) ROUTER_URL=http://${DEPLOYMENT_NAME}-${NAMESPACE}-routing-service.hyperpod-inference-system.svc.cluster.local:443/v1/chat/completions
短提示 (低於閾值,直接至解碼器)
字符少於routingThreshold繞過預填充物並直接前往解碼器的請求:
kubectl run curl-short --rm -it --image=curlimages/curl --restart=Never -- \ curl -s -k -X POST "$ROUTER_URL" \ -H "Content-Type: application/json" \ -d '{ "model": "/opt/ml/model", "messages": [{"role": "user", "content": "What is disaggregated prefill-decode in one sentence?"}], "max_tokens": 80, "temperature": 0.0 }'
長提示 (超過閾值,DPD 路徑)
請求超過透過 KV 快取運算預填充器的閾值路由,然後傳送至解碼器進行權杖產生:
kubectl run curl-long --rm -it --image=curlimages/curl --restart=Never -- sh -c ' LONG="" i=0; while [ $i -lt 600 ]; do LONG="${LONG}The quick brown fox jumps over the lazy dog. "; i=$((i+1)); done curl -s -k -X POST "'"$ROUTER_URL"'" \ -H "Content-Type: application/json" \ -d "{\"model\":\"/opt/ml/model\",\"messages\":[{\"role\":\"user\",\"content\":\"${LONG}\"}],\"max_tokens\":30,\"temperature\":0.0}" '
驗證 KV 傳輸
傳送長提示後,檢查解碼器日誌以確認 KV 快取已傳輸:
kubectl logs $DECODE_POD -n ${NAMESPACE} -c decode-${DEPLOYMENT_NAME} \ | grep -E "Retrieved.*tokens.*throughput" | tail -2
預期的輸出 (每個 TP 排名一行):
[Worker_TP5] [LMCache INFO] [req_id=cmpl-...] Retrieved 6035 out of 6035 required tokens (from 6035 total tokens). size: 0.2344 gb, cost 1.3304 ms, throughput: 176.1686 GB/s
Retrieved N out of N required tokens N > 0 的 會確認 KV 快取成功跨過 NIXL 頻道。如果您看到 Retrieved 0 out of N,解碼器會下降回本機重新計算 — 請參閱 分解預填充和解碼 (DPD) 部署問題。
您也可以在路由器日誌中驗證路由決策:
kubectl logs $ROUTER_POD -n hyperpod-inference-system -c router-container --tail=20 \ | grep -E "Conditional routing"
對於長提示,您應該會看到:
[INFO] Conditional routing: estimated_tokens=6750, threshold=4096, disaggregate=True
針對簡短提示:
[INFO] Conditional routing: estimated_tokens=12, threshold=4096, disaggregate=False
注意
若要透過 SageMaker AI 端點叫用,請在 endpointName中設定 InferenceEndpointConfig。如果endpointName未設定 ,則不會建立 SageMaker AI 端點,而且只有直接 ALB 調用可用。
可觀測性
在 metrics.enabled: true中設定 以啟用指標InferenceEndpointConfig。DPD 指標可在 HyperPod 推論儀表板中使用。如需詳細資訊,請參閱在 HyperPod 叢集上實作推論可觀測性。
可使用下列 DPD 特定指標:
| 指標 | 說明 |
|---|---|
| E2E TTFT | 到第一個字符的整體時間 (預先填充 + KV 轉移 + 路由) |
| 預先填入 TTFT | 僅限預填充器的延遲 |
| 預填充佇列 | 等待預先填入的請求數量 |
| 解碼佇列 | 在解碼器上等待的請求數 |
| 預先填入時間 | 預先填入運算所花費的時間 |
| 解碼延遲 | 每個字符輸出延遲 (TPOT) |
| KV 傳輸時間 | 從預填充器傳輸 KV 快取到解碼器的時間 |
| DPD 路由計數 | 分解與備用 (閾值不足) 請求 |
調校您的 DPD 部署
下表提供根據您在指標儀表板中觀察到的症狀調校 DPD 的快速參考。
| Config | 它的功能 | 預設 | 何時調整 |
|---|---|---|---|
pdSpec.routingThreshold |
要透過預填充物路由的最小輸入字符。低於此閾值的請求會直接傳送至解碼器。 | 4096 |
預設值適用於大多數工作負載。由於在短提示上不必要的 KV 傳輸,設定過低會增加 TTFT,同時設定過高限制 TPOT 改善,因為較少的請求會採用 DPD 路徑。 |
pdSpec.prefillSpec.replicas |
預填充 Pod 的數量。 | 1 |
如果預填充佇列深度很高,請向上擴展,以改善預填充 TTFT。 |
PD_BUFFER_SIZE |
用於傳入 KV 傳輸的解碼器 GPU 緩衝區 (每個排名)。8 GiB 會在 TP=8 時為 70B 保留大約 35 個傳輸中的 6K-token傳輸。 | "8589934592" (8 GiB) |
增加 以處理更多並行 KV 傳輸。如果您看到記憶體問題,請減少 。增加時,您可能需要降低解碼器--gpu-memory-utilization上的 ,才能為較大的緩衝區釋放 GPU 記憶體。 |
--gpu-memory-utilization |
用於權重、啟用和 KV 快取的 GPU 記憶體 vLLM 分數。 | 0.75 |
在長輸入上增加更多 KV 快取標頭空間。風險:預先填入 OOM,因為預先填入也需要記憶體才能啟用。使用實際輸入長度分佈進行測試。 |
--max-num-seqs |
每個工作者批次的最大並行序列數。 | 16 (預填充物)、 32(解碼器) |
提高 以在負載下進行更好的批次處理。如果達到預填充物上的 OOM,則降低。透過 設定每個角色pdSpec.{prefillSpec,decodingSpec}.args。 |
intelligentRoutingSpec.routingStrategy |
當有多個複本存在時,路由器如何選取預填器。 | prefixaware |
使用 roundrobin 將負載平均分配到多個預填充複本。使用 prefixaware或 kvaware搭配單一預填器,或在提示共用常見字首 (系統提示、聊天歷史記錄) 時,將快取命中最大化。 |
使用實際工作負載和輸入長度分佈進行測試。
若要套用組態變更,請編輯您的部署 YAML 並重新套用:
kubectl apply -f inference_endpoint_dpd_config.yaml
已知限制
-
對於具有 70B 或更多參數的密集型模型,建議使用 DPD。較小的模型和 Mixture-of-Experts 模型通常不會受益於分解。
-
目前版本支援每個端點的單一解碼部署。未來版本預計支援多個解碼部署。
-
效能在 ml.p5.48xlarge 與 Llama 3.3 70B 上驗證最多 64 個並行請求。
-
若要從 DPD 部署還原至標準共置部署,請套用
InferenceEndpointConfig不含 的新pdSpec。
如需 DPD 部署的故障診斷,請參閱 分解預填充和解碼 (DPD) 部署問題。