全部產品
Search
文件中心

Container Service for Kubernetes:部署Dynamo PD分離推理服務

更新時間:Aug 22, 2025

本文以Qwen3-32B模型為例,示範如何在ACK中部署Dynamo PD分離架構的模型推理服務。

背景知識

  • Qwen3-32B

    Qwen3-32B 是通義千問系列最新一代的大型語言模型,基於328億參數的密集模型架構,兼具卓越的推理能力與高效的對話效能。其最大特色在於支援思考模式與非思考模式的無縫切換。在複雜邏輯推理、數學計算和代碼產生任務中表現出眾,而在日常對話情境下也可高效響應。模型具備出色的指令遵循、多輪對話、角色扮演和創意寫作能力,並在Agent任務中實現領先的工具調用表現。原生支援32K上下文,結合YaRN技術可擴充至131K。同時,支援100多種語言,具備強大的多語言理解與翻譯能力,適用於全球化應用情境。有關更多詳細資料,請參閱部落格GitHub文檔

  • Dynamo

    Dynamo 是NVIDIA推出的一款高吞吐、低延遲的推理架構,專門用於在多節點分布式環境中為LLM模型提供推理服務。image.png

    其核心特性包括如下所示,更多關於Dynamo架構的資訊,請參見Dynamo GitHubDynamo文檔

    • 引擎無關性:它不綁定於特定的推理引擎,可以靈活支援TensorRT-LLM、vLLM、SGLang等多種後端。

    • LLM專屬最佳化能力

      • Prefill與Decode分離推理,通過將Prefill和Decode分開部署,降低推理延遲,提升系統吞吐。

      • 動態GPU調度,根據即時變化的負載需求來最佳化效能。

      • LLM感知的請求路由,可以根據節點KVCache進行路由,避免不必要的KVCache重計算。

      • 加速資料轉送,利用NIXL技術來加速中間計算結果及KVCache傳輸。

      • KVCache卸載,可以將KVCache卸載到記憶體、磁碟甚至雲端硬碟上,從而提升系統總輸送量。

      • 高效能與高擴充性,核心由 Rust 語言構建以追求極致效能,同時提供Python介面以方便使用者進行擴充。

      • 完全開源,Dynamo完全開源,並遵循透明的、開源軟體優先的開發理念。

  • PD分離

    Prefill/Decode分離架構,是當前主流的LLM推理最佳化技術,旨在解決推理過程中兩個核心階段的資源需求衝突問題。LLM的推理過程可分為兩個階段:

    • Prefill (提示詞處理) 階段:此階段一次性處理使用者輸入的全部提示詞(Prompt),並行計算所有輸入Token的注意力,並產生初始的KV緩衝。這個過程是計算密集型(Compute-Bound)的,需要強大的並行計算能力,但只在請求開始時執行一次。

    • Decode (解碼產生) 階段:此階段是自迴歸過程,模型根據已有的KV緩衝,逐個產生新的Token。每一步的計算量很小,但需要反覆、快速地從顯存中載入巨大的模型權重和KV緩衝,因此是記憶體頻寬密集型(Memory-Bound)的。image.png

    核心矛盾在於將這兩種特性迥異的任務混合在同一GPU上調度,效率極低。推理引擎在處理多個使用者請求時往往會採用連續批處理(Continuous Batching)的方式,將不同請求的Prefill階段和Decode階段放在一個批次裡調度。由於Prefill階段需處理完整提示詞(計算複雜度高),而Decode階段僅需產生單token(計算複雜度低),若在同一批次中調度,Decode階段會因序列長度差異與資源競爭導致時延增加,進而增加系統整體延遲並降低輸送量。

    image.png

    PD分離架構的解決方案就是將這兩個階段解耦,將Prefill和Decode階段分開部署在不同GPU上。通過這種分離,系統可以針對Prefill和Decode不同特徵進行最佳化,避免資源爭搶,從而顯著降低產生每個輸出 token 的平均時間(TPOT),提升系統吞吐。

  • RoleBasedGroup

    RoleBasedGroup(RBG)是阿里雲Container Service團隊設計的一種新的工作負載,為瞭解決PD分離架構在Kubernetes叢集中大規模部署及營運的難題。該專案已開源,更多資訊請查看RBG Github

    RBG API設計如下圖所示,它由一組Role構成一個Group整體,每個Role可以基於StatefulSet/Deployment/LWS構建。其核心特性如下:

    • 靈活的多角色定義:RBG支援定義任意數量任意名稱的Role;支援定義Role間的依賴關係,可以按指定順序啟動Role;可以按照Role維度彈性擴縮容。

    • Runtime:具備Group內部的自動服務發現能力;支援多種重啟策略;支援變換;支援Gang調度。

      image.png

前提條件

  • 已建立ACK叢集且叢集版本為1.22及以上,並且已經為叢集添加GPU節點。具體操作,請參見建立ACK託管叢集為叢集添加GPU節點

    本文要求叢集中GPU卡>=6, 單個GPU卡顯存>=32GB。推薦使用ecs.ebmgn8is.32xlarge規格,更多規格資訊可參考ECS Bare Metal Instance規格
  • 已安裝ack-rbgs組件。組件安裝步驟如下。

    登入Container Service管理主控台,在左側導覽列選擇叢集列表單擊目的地組群名稱,進入叢集詳情頁面,使用Helm為目的地組群安裝ack-rbgs組件。您無需為組件配置應用程式名稱命名空間,單擊下一步後會出現一個請確認的彈框,單擊是,即可使用預設的應用程式名稱(ack-rbgs)和命名空間(rbgs-system)。然後選擇Chart 版本為最新版本,單擊確定即可完成ack-rbgs組件的安裝。

    image

模型部署

部署Dynamo PD分離架構推理服務。Dynamo PD分離時序圖如下所示。

  • 使用者請求首先發送給processor組件,經由router選出合適的Decode Worker,將請求轉寄給Decode Worker。

  • 由Decode Worker判斷是否prefill計算是在本地完成還是遠程完成。如果需要遠程計算,則向PrefillQueue中發送請求。

  • PrefillWorker從Queue擷取請求後進行Prefill計算。等計算完成後,將Prefill KVCache傳輸給Decode Worker。

image.png

步驟一:準備Qwen3-32B模型檔案

  1. 執行以下命令從ModelScope下載Qwen-32B模型。

    請確認是否已安裝git-lfs外掛程式,如未安裝可執行yum install git-lfs或者apt-get install git-lfs安裝。更多的安裝方式,請參見安裝git-lfs
    git lfs install
    GIT_LFS_SKIP_SMUDGE=1 git clone https://www.modelscope.cn/Qwen/Qwen3-32B.git
    cd Qwen3-32B/
    git lfs pull
  2. 登入OSS控制台,查看並記錄已建立的Bucket名稱。如何建立Bucket,請參見建立儲存空間。在OSS中建立目錄,將模型上傳至OSS。

    關於ossutil工具的安裝和使用方法,請參見安裝ossutil
    ossutil mkdir oss://<your-bucket-name>/Qwen3-32B
    ossutil cp -r ./Qwen3-32B oss://<your-bucket-name>/Qwen3-32B
  3. 建立PV和PVC。為目的地組群配置名為llm-model的儲存卷PV和儲存聲明PVC。具體操作,請參見建立PV和PVC

    控制台操作樣本

    1. 建立PV。

      • 登入Container Service管理主控台,在左側導覽列選擇叢集列表

      • 叢集列表頁面,單擊目的地組群名稱,然後在左側導覽列,選擇儲存 > 儲存卷

      • 儲存卷頁面,單擊右上方的建立

      • 建立儲存卷對話方塊中配置參數。

        以下為樣本PV的基本配置資訊:

        配置項

        說明

        儲存卷類型

        OSS

        名稱

        llm-model

        訪問認證

        配置用於訪問OSS的AccessKey ID和AccessKey Secret。

        Bucket ID

        選擇上一步所建立的OSS Bucket。

        OSS Path

        選擇模型所在的路徑,如/Qwen3-32B

    2. 建立PVC。

      • 叢集列表頁面,單擊目的地組群名稱,然後在左側導覽列,選擇儲存 > 儲存聲明

      • 儲存聲明頁面,單擊右上方的建立

      • 建立儲存聲明頁面中,填寫介面參數。

        以下為樣本PVC的基本配置資訊:

        配置項

        說明

        儲存宣告類型

        OSS

        名稱

        llm-model

        分配模式

        選擇已有儲存卷。

        已有儲存卷

        單擊選擇已有儲存卷連結,選擇已建立的儲存卷PV。

    kubectl操作樣本

    1. 建立llm-model.yaml檔案,該YAML檔案包含Secret靜態卷PV靜態卷PVC等配置,樣本YAML檔案如下所示。

      apiVersion: v1
      kind: Secret
      metadata:
        name: oss-secret
      stringData:
        akId: <your-oss-ak> # 配置用於訪問OSS的AccessKey ID
        akSecret: <your-oss-sk> # 配置用於訪問OSS的AccessKey Secret
      ---
      apiVersion: v1
      kind: PersistentVolume
      metadata:
        name: llm-model
        labels:
          alicloud-pvname: llm-model
      spec:
        capacity:
          storage: 30Gi 
        accessModes:
          - ReadOnlyMany
        persistentVolumeReclaimPolicy: Retain
        csi:
          driver: ossplugin.csi.alibabacloud.com
          volumeHandle: llm-model
          nodePublishSecretRef:
            name: oss-secret
            namespace: default
          volumeAttributes:
            bucket: <your-bucket-name> # bucket名稱
            url: <your-bucket-endpoint> # Endpoint資訊,如oss-cn-hangzhou-internal.aliyuncs.com
            otherOpts: "-o umask=022 -o max_stat_cache_size=0 -o allow_other"
            path: <your-model-path> # 本樣本中為/Qwen3-32B/
      ---
      apiVersion: v1
      kind: PersistentVolumeClaim
      metadata:
        name: llm-model
      spec:
        accessModes:
          - ReadOnlyMany
        resources:
          requests:
            storage: 30Gi
        selector:
          matchLabels:
            alicloud-pvname: llm-model
    2. 建立Secret建立靜態卷PV建立靜態卷PVC

      kubectl create -f llm-model.yaml

步驟二:安裝ETCD及NATS服務

Dynamo架構中跨節點通訊使用的是NIXL。NIXL啟動時會向ETCD註冊,從而實現相互發現。NATS服務主要用於Prefill和Decode Worker間訊息傳遞。因此部署推理服務前,需要先部署ETCD及NATS服務。

  1. 執行以下命令建立etcd.yaml並部署ETCD服務。

    展開查看相關YAML樣本。

    apiVersion: v1
    kind: Service
    metadata:
      name: etcd
      labels:
        app: etcd
    spec:
      ports:
        - port: 2379
          name: client
        - port: 2380
          name: peer
      clusterIP: None # Enables headless service mode
      selector:
        app: etcd
    ---
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: etcd
      labels:
        app: etcd
    spec:
      selector:
        matchLabels:
          app: etcd
      serviceName: "etcd"
      replicas: 1
      template:
        metadata:
          labels:
            app: etcd
        spec:
          containers:
            - name: etcd
              # image: bitnami/etcd:3.5.19
              image: ac2-registry.cn-hangzhou.cr.aliyuncs.com/ac2/etcd:3.6.1
              volumeMounts:
                - name: data
                  mountPath: /var/lib/etcd
              env:
                - name: ETCDCTL_API
                  value: "3"
                - name: ALLOW_NONE_AUTHENTICATION
                  value: "yes"
          volumes:
            - name: data
              emptyDir: {}
    kubectl apply -f etcd.yaml
  2. 執行以下命令建立nats.yaml並部署NATS服務。

    展開查看相關YAML樣本。

    apiVersion: v1
    kind: Service
    metadata:
      name: nats
      labels:
        app: nats
    spec:
      ports:
        - port: 4222
          name: client
        - port: 8222
          name: management
        - port: 6222
          name: cluster
      selector:
        app: nats
      type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nats
      labels:
        app: nats
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nats
      template:
        metadata:
          labels:
            app: nats
        spec:
          containers:
            - name: nats
              # image: nats:latest
              image: ac2-registry.cn-hangzhou.cr.aliyuncs.com/ac2/nats:2.11.5
              args:
                - -js
                - --trace
                - -m
                - "8222"
              ports:
                - containerPort: 4222
                - containerPort: 8222
                - containerPort: 6222
    kubectl apply -f nats.yaml

步驟三:部署Dynamo PD分離架構的推理服務

本文使用RBG部署2P1D Dynamo推理服務,部署架構圖如下所示。 Prefill和Decode均採用了TP=2的方式部署。

image.png

  1. 使用dynamo-configs.yaml配置qwen3模型及Dynamo架構相關的設定檔。

    展開查看相關YAML樣本。

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: dynamo-configs
    data:
      pd_disagg.py: |
        from components.frontend import Frontend
        from components.kv_router import Router
        from components.processor import Processor
    
        Frontend.link(Processor).link(Router)
    
      qwen3.yaml: |
        Common:
          model: /models/Qwen3-32B/
          kv-transfer-config: '{"kv_connector":"DynamoNixlConnector"}'
          router: round-robin
          # Number of tokens in a batch for more efficient chunked transfers to GPUs.
          block-size: 128
          max-model-len: 2048
          max-num-batched-tokens: 2048
          disable-log-requests: true
    
        Frontend:
          served_model_name: qwen
          endpoint: dynamo.Processor.chat/completions
          port: 8000
    
        Processor:
          common-configs: [ model, router ]
    
        VllmWorker:
          common-configs: [ model, kv-transfer-config, router, block-size, max-model-len, disable-log-requests ]
          # Enable prefill at different workers.
          remote-prefill: true
          # Disable local prefill so only disaggregated prefill is used.
          conditional-disagg: false
          gpu-memory-utilization: 0.95
          tensor-parallel-size: 1
          ServiceArgs:
            workers: 1
            resources:
              gpu: 1
    
        PrefillWorker:
          common-configs: [ model, kv-transfer-config, block-size, max-model-len, max-num-batched-tokens, gpu-memory-utilization, disable-log-requests ]
          tensor-parallel-size: 1
          gpu-memory-utilization: 0.95
          ServiceArgs:
            workers: 1
            resources:
              gpu: 1
    
    kubectl apply -f dynamo-configs.yaml
  2. 準備Dynamo Runtime鏡像。

    具體操作,請參見Dynamo社區文檔擷取,或製作使用vllm作為推理架構的Dynamo Runtime容器鏡像。

  3. 執行以下命令建立dynamo.yaml並部署服務。

    展開查看相關YAML樣本。

    apiVersion: workloads.x-k8s.io/v1alpha1
    kind: RoleBasedGroup
    metadata:
      name: dynamo-pd
      namespace: default
    spec:
      roles:
        - name: processor
          replicas: 1
          template:
            spec:
              containers:
                - command:
                    - sh
                    - -c
                    - cd /workspace/examples/llm; dynamo serve graphs.pd_disagg:Frontend -f ./configs/qwen3.yaml
                  env:
                    - name: DYNAMO_NAME
                      value: dynamo
                    - name: DYNAMO_NAMESPACE
                      value: default
                    - name: ETCD_ENDPOINTS
                      value: http://etcd:2379
                    - name: NATS_SERVER
                      value: nats://nats:4222
                    - name: DYNAMO_RP_TIMEOUT
                      value: "60"
                  image: #步驟2中所構建的Dynamo Runtime鏡像地址
                  name: processor
                  ports:
                    - containerPort: 8000
                      name: health
                      protocol: TCP
                    - containerPort: 9345
                      name: request
                      protocol: TCP
                    - containerPort: 443
                      name: api
                      protocol: TCP
                    - containerPort: 9347
                      name: metrics
                      protocol: TCP
                  readinessProbe:
                    initialDelaySeconds: 30
                    periodSeconds: 30
                    tcpSocket:
                      port: 8000
                  resources:
                    limits:
                      cpu: "8"
                      memory: 12Gi
                    requests:
                      cpu: "8"
                      memory: 12Gi
                  volumeMounts:
                    - mountPath: /models/Qwen3-32B/
                      name: model
                    - mountPath: /workspace/examples/llm/configs/qwen3.yaml
                      name: dynamo-configs
                      subPath: qwen3.yaml
                    - mountPath: /workspace/examples/llm/graphs/pd_disagg.py
                      name: dynamo-configs
                      subPath: pd_disagg.py
              volumes:
                - name: model
                  persistentVolumeClaim:
                    claimName: llm-model
                - configMap:
                    name: dynamo-configs
                  name: dynamo-configs
        - name: prefill
          replicas: 2
          template:
            spec:
              containers:
                - command:
                    - sh
                    - -c
                    - cd /workspace/examples/llm; dynamo serve components.prefill_worker:PrefillWorker -f ./configs/qwen3.yaml
                  env:
                    - name: DYNAMO_NAME
                      value: dynamo
                    - name: DYNAMO_NAMESPACE
                      value: default
                    - name: ETCD_ENDPOINTS
                      value: http://etcd:2379
                    - name: NATS_SERVER
                      value: nats://nats:4222
                    - name: DYNAMO_RP_TIMEOUT
                      value: "60"
                  image: #步驟2中所構建的Dynamo Runtime鏡像地址
                  name: prefill-worker
                  resources:
                    limits:
                      cpu: "12"
                      memory: 50Gi
                      nvidia.com/gpu: "2"
                    requests:
                      cpu: "12"
                      memory: 50Gi
                      nvidia.com/gpu: "2"
                  volumeMounts:
                    - mountPath: /models/Qwen3-32B/
                      name: model
                    - mountPath: /workspace/examples/llm/configs/qwen3.yaml
                      name: dynamo-configs
                      subPath: qwen3.yaml
              volumes:
                - name: model
                  persistentVolumeClaim:
                    claimName: llm-model
                - configMap:
                    name: dynamo-configs
                  name: dynamo-configs
        - name: decoder
          replicas: 1
          template:
            spec:
              containers:
                - command:
                    - sh
                    - -c
                    - cd /workspace/examples/llm; dynamo serve components.worker:VllmWorker -f ./configs/qwen3.yaml --service-name VllmWorker
                  env:
                    - name: DYNAMO_NAME
                      value: dynamo
                    - name: DYNAMO_NAMESPACE
                      value: default
                    - name: ETCD_ENDPOINTS
                      value: http://etcd:2379
                    - name: NATS_SERVER
                      value: nats://nats:4222
                    - name: DYNAMO_RP_TIMEOUT
                      value: "60"
                  image: #步驟2中所構建的Dynamo Runtime鏡像地址
                  name: vllm-worker
                  resources:
                    limits:
                      cpu: "12"
                      memory: 50Gi
                      nvidia.com/gpu: "2"
                    requests:
                      cpu: "12"
                      memory: 50Gi
                      nvidia.com/gpu: "2"
                  volumeMounts:
                    - mountPath: /models/Qwen3-32B/
                      name: model
                    - mountPath: /workspace/examples/llm/configs/qwen3.yaml
                      name: dynamo-configs
                      subPath: qwen3.yaml
              volumes:
                - name: model
                  persistentVolumeClaim:
                    claimName: llm-model
                - configMap:
                    name: dynamo-configs
                  name: dynamo-configs
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: dynamo-service
    spec:
      type: ClusterIP
      ports:
        - port: 8000
          protocol: TCP
          targetPort: 8000
      selector:
        rolebasedgroup.workloads.x-k8s.io/name: dynamo-pd
        rolebasedgroup.workloads.x-k8s.io/role: processor
    kubectl apply -f ./dynamo.yaml

步驟四:驗證推理服務

  1. 執行以下命令,在推理服務與本地環境之間建立連接埠轉寄。

    重要

    kubectl port-forward建立的連接埠轉寄不具備生產層級的可靠性、安全性和擴充性,因此僅適用於開發和調試目的,不適合在生產環境使用。更多關於Kubernetes叢集內生產可用的網路方案的資訊,請參見Ingress管理

    kubectl port-forward svc/dynamo-service 8000:8000

    預期輸出:

    Forwarding from 127.0.0.1:8000 -> 8000
    Forwarding from [::1]:8000 -> 8000
  2. 執行以下命令,向模型推理服務發送了一條樣本的模型推理請求。

    curl http://localhost:8000/v1/chat/completions   -H "Content-Type: application/json"   -d '{"model": "qwen","messages": [{"role": "user","content": "測試一下"}],"stream":false,"max_tokens": 30}'

    預期輸出:

    {"id":"31ac3203-c5f9-4b06-a4cd-4435a78d3b35","choices":[{"index":0,"message":{"content":"<think>\n好的,使用者發來“測試一下”,我需要先確認他們的意圖。可能是在測試我的反應速度或者功能,也可能是想","refusal":null,"tool_calls":null,"role":"assistant","function_call":null,"audio":null},"finish_reason":"length","logprobs":null}],"created":1753702438,"model":"qwen","service_tier":null,"system_fingerprint":null,"object":"chat.completion","usage":null}

    輸出結果表明模型可以根據給定的輸入(在這個例子中是一條測試訊息)產生相應的回複。

相關文檔

  • 為單機/多機推理配置彈性擴縮容

    針對LLM模型服務的動態負載波動問題,Kubernetes HPA結合ACK的ack-alibaba-cloud-metrics-adapter組件,可根據CPU/記憶體/GPU利用率及自訂指標實現Pod的動態Auto Scaling,保障服務穩定性與資源高效利用。

  • 基於Fluid配置分布式緩衝實現模型加速

    LLM 模型通常包含超過10GB的權重檔案,從儲存服務(如 OSS、NAS 等)拉取這些大檔案時,容易因長時間延遲和冷啟動問題影響效能。Fluid 通過在 Kubernetes 叢集節點上構建分布式檔案快取系統,整合多個節點的儲存與頻寬資源;同時,它從應用程式端最佳化模型檔案的讀取機制,從而顯著加速模型載入過程。