在 A4 虚拟机上使用 Dynamo 和 SGLang,通过 PD 解耦在 GKE 上部署 Llama 3.1 405B

本教程介绍了如何在 Google Cloud上的 Google Kubernetes Engine (GKE) 上部署和应用 Llama 3.1 405B (nvidia/Llama-3.1-405B-Instruct-FP8),这是一个量化为 FP8 的 4050 亿参数指令调优模型。该部署使用 Cluster Toolkit、两个 A4 (a4-highgpu-8g) 虚拟机 (VM) 实例(总共 16 个 NVIDIA B200 GPU)、NVIDIA Dynamo 以及采用单主机预填充解码 (PD) 解耦的 SGLang 服务框架。

在本教程中介绍的部署配置中,您将使用 Cluster Toolkit 在标准模式下预配 GKE 集群。该集群包含两个通过 GPUDirect 远程直接内存访问 (RDMA) 网络连接的 a4-highgpu-8g 节点。然后,您可以使用 Grove 组调度安装 KAI 调度器和 NVIDIA Dynamo 平台。最后,您将部署一个 DynamoGraphDeployment 自定义资源,该资源通过张量并行和 FP8 KV 缓存,将预填充和解码分离到两个单主机八 GPU 工作器中。

目标

  • 安装 Cluster Toolkit,并在标准模式下预配一个双节点 A4 GKE 集群。
  • 在集群上安装 KAI 调度器和 NVIDIA Dynamo 平台,并启用 Grove 组调度。
  • 部署一个 PD 分离式 SGLang 推理服务器,其中包含一个单主机 A4 预填充工作器和一个单主机 A4 解码工作器。
  • 向 Dynamo 前端路由器发送对话补全请求。
  • 运行服务基准工作负载。
  • 清理已部署的资源。

费用

在本文档中,您将使用Google Cloud的以下收费组件:

如需根据您的预计使用量来估算费用,请使用价格计算器。

准备工作

为本教程设置环境:

  1. 安装并初始化 Google Cloud CLI,然后安装 kubectl 和 Helm(3.10 或更高版本)。如果您使用 Cloud Shell,则这些工具已预安装。
  2. 如果您是在 Linux 或 macOS 工作站(而非 Cloud Shell)中运行本教程,请安装所需的Cluster Toolkit 依赖项,例如 Terraform 和 Git。
  3. 在 Google Cloud 项目中启用 Kubernetes Engine API、Compute Engine API、Cloud Storage API、Identity and Access Management API、Cloud Resource Manager API 和 Service Usage API:

    启用 API

获取 Hugging Face 访问令牌

您需要拥有 Hugging Face 访问令牌才能使用本教程。您可以在 Hugging Face 注册免费账号。拥有账号后,生成访问令牌:

  1. 在欢迎使用 Hugging Face 页面上,点击您的账号头像,然后选择访问令牌。
  2. 在访问令牌页面上,点击创建新令牌。
  3. 选择读取令牌类型,然后输入令牌名称。
  4. 系统会显示您的访问令牌。将令牌保存在安全的位置。

所需的角色

如需获得完成本教程所需的权限,请让您的管理员为您授予项目的以下 IAM 角色:

如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限。

您也可以通过自定义角色或其他预定义角色来获取所需的权限。

设置环境变量

导出您在本教程中使用的环境变量:

export PROJECT_ID="YOUR_PROJECT_ID"
export REGION="YOUR_REGION"
export ZONE="YOUR_ZONE"
export CLUSTER_NAME="YOUR_CLUSTER_NAME"
export RESERVATION_NAME="YOUR_RESERVATION_NAME"
export GCS_BUCKET="YOUR_BUCKET_NAME"
export HF_TOKEN="YOUR_HF_TOKEN"
export CLUSTER_TOOLKIT_VERSION="v1.104.0"
export DYNAMO_RELEASE_VERSION="1.5.0"

gcloud config set project "${PROJECT_ID}"
gcloud config set billing/quota_project "${PROJECT_ID}"

替换以下内容:

  • YOUR_PROJECT_ID:您的 Google Cloud项目的 ID。
  • YOUR_REGION:A4 容量所在的区域以及您要部署集群的区域,例如 us-central1。
  • YOUR_ZONE:A4 容量所在的可用区,例如 us-central1-b。
  • YOUR_CLUSTER_NAME:GKE 集群和 Cluster Toolkit 部署的名称。请使用不超过 20 个字符的名称,以便生成的节点池服务账号 ID (YOUR_CLUSTER_NAME-gke-np-sa) 保持在 30 个字符的 Identity and Access Management (IAM) 限制范围内。
  • YOUR_RESERVATION_NAME:A4 预留的名称。
  • YOUR_BUCKET_NAME:存储 Cluster Toolkit 的 Terraform 状态的 Cloud Storage 存储桶的全球唯一名称。
  • YOUR_HF_TOKEN:您的 Hugging Face 访问令牌。

创建 GKE 集群

下载 Cluster Toolkit,并在标准模式下预配一个 GKE 集群,该集群具有两个 a4-highgpu-8g 节点、GPUDirect RDMA 网络和 DRA 支持:

  1. 登录 Google Cloud CLI 并为 Terraform 生成应用默认凭证:

    gcloud auth login
    gcloud auth application-default login
  2. 下载并解压缩 CLUSTER_TOOLKIT_VERSION (v1.104.0) 中指定的版本的预构建 Cluster Toolkit 软件包:

    TAG="${CLUSTER_TOOLKIT_VERSION:-v1.104.0}"
    OS="linux"
    ARCH="amd64"
    mkdir -p cluster-toolkit && curl -L "https://github.com/GoogleCloudPlatform/cluster-toolkit/releases/download/${TAG}/gcluster_bundle_${OS}_${ARCH}.tgz" | tar -xz -C cluster-toolkit

    如果您在 macOS 或 arm64 工作站上运行此命令,请将 OS="mac" 或 ARCH="arm64" 设置为与您的平台匹配。

  3. 如需存储 Cluster Toolkit 部署的 Terraform 状态,请创建一个启用了对象版本控制的 Cloud Storage 存储桶:

    gcloud storage buckets create "gs://${GCS_BUCKET}" \
        --default-storage-class=STANDARD \
        --project="${PROJECT_ID}" \
        --location="${REGION}" \
        --uniform-bucket-level-access
    gcloud storage buckets update "gs://${GCS_BUCKET}" --versioning
  4. 为两个 a4-highgpu-8g 节点创建 cluster-toolkit/examples/gke-a4/gke-a4-deployment.yaml 部署配置文件:

    cat <<EOF > cluster-toolkit/examples/gke-a4/gke-a4-deployment.yaml
    terraform_backend_defaults:
      type: gcs
      configuration:
        bucket: ${GCS_BUCKET}
    
    vars:
      project_id: ${PROJECT_ID}
      deployment_name: ${CLUSTER_NAME}
      region: ${REGION}
      zone: ${ZONE}
      static_node_count: 2
      authorized_cidr: 0.0.0.0/0
      reservation_affinity:
        consume_reservation_type: SPECIFIC_RESERVATION
        specific_reservations:
        - name: ${RESERVATION_NAME}
    EOF

    默认情况下,部署文件配置为使用特定预留。如果您没有特定预留,则可以在部署集群之前更新 cluster-toolkit/examples/gke-a4/gke-a4-deployment.yaml,以使用其他使用选项,例如 Spot 虚拟机或灵活启动型虚拟机。如需了解配置说明,请参阅 GKE 使用选项。

  5. 切换到 cluster-toolkit 目录,使用 gcluster deploy 命令部署 GKE 集群,然后返回到工作目录:

    cd cluster-toolkit
    ./gcluster deploy \
        -d examples/gke-a4/gke-a4-deployment.yaml \
        examples/gke-a4/gke-a4.yaml \
        --auto-approve -w
    cd ..

    创建集群大约需要 20 到 30 分钟。如果您在不使用 --auto-approve 标志的情况下运行 ./gcluster deploy,则在系统提示时输入 a 即可应用建议的更改。

  6. 配置 kubectl 凭据以与您的集群通信:

    gcloud container clusters get-credentials "${CLUSTER_NAME}" \
        --location="${REGION}" \
        --project="${PROJECT_ID}"

安装 KAI 调度器和 NVIDIA Dynamo

通过创建 Hugging Face Secret 并安装 KAI 调度器和 NVIDIA Dynamo 平台(采用 Grove 帮派调度)来准备集群:

  1. 创建一个名为 hf-secret 的 Kubernetes Secret,用于存储您的 Hugging Face 访问令牌:

    kubectl create secret generic hf-secret \
        --from-literal=hf_api_token="${HF_TOKEN}" \
        --dry-run=client -o yaml | kubectl apply -f -
  2. 下载 NVIDIA Dynamo 平台 Helm chart (v1.5.0),安装 KAI 调度器,然后安装启用了 Grove 的 Dynamo 平台:

    RELEASE_VERSION="${DYNAMO_RELEASE_VERSION:-1.5.0}"
    helm fetch "https://helm.ngc.nvidia.com/nvidia/ai-dynamo/charts/dynamo-platform-${RELEASE_VERSION}.tgz"
    tar -zxf "dynamo-platform-${RELEASE_VERSION}.tgz"
    
    helm upgrade --install kai-scheduler ./dynamo-platform/charts/kai-scheduler \
        --set scheduler.args.default-staleness-grace-period="-1s" \
        --set topologyMigration.enabled=false
    
    kubectl wait --for=condition=Available deployment/kai-operator --timeout=120s
    until kubectl get deployment/queue-controller >/dev/null 2>&1; do sleep 2; done
    kubectl wait --for=condition=Available deployment/queue-controller --timeout=120s
    
    helm upgrade --install dynamo-platform ./dynamo-platform \
        --set global.grove.install=true \
        --set global.grove.enabled=true \
        --set global.kai-scheduler.enabled=true

部署单主机分离式 SGLang 服务器

工作负载清单 (llama3.1-405b-singlehost-a4.yaml) 定义了一个 Kubernetes ResourceClaimTemplate (all-mrdma),该模板通过 DRA 分配节点的**多 NIC** RDMA 设备 (mrdma.google.com),以及一个启用了 Grove 组调度的 NVIDIA Dynamo DynamoGraphDeployment (llama3-405b-a4-disagg)。部署包括以下内容:

  • 前端 (Frontend):运行一个路由器副本,用于接受客户端请求、发现已注册的预填充和解码工作器,以及协调解耦请求路由。
  • 预填充工作器 (Prefill):在一个 a4-highgpu-8g 节点上运行单主机工作器,该节点配备 8 个 NVIDIA B200 GPU。启动时,Pod 会获取 NCCL/gIB 环境,将 nvidia/Llama-3.1-405B-Instruct-FP8 检查点从 Hugging Face Hub 下载到节点的本地 NVMe SSD,并使用以下标志在 --disaggregation-mode prefill 中启动 python3 -m dynamo.sglang:
    • --tensor-parallel-size 8
    • --kv-cache-dtype fp8_e4m3
    • --context-length 16384
    • --mem-fraction-static 0.85
  • 解码工作器 (Decode):在第二个 a4-highgpu-8g 节点上运行单主机工作器,该节点配备 8 个 NVIDIA B200 GPU。启动时,Pod 会将模型权重缓存在节点的本地 NVMe SSD 上,并使用以下标志在 --disaggregation-mode decode 中启动 python3 -m dynamo.sglang:
    • --tensor-parallel-size 8
    • --kv-cache-dtype fp8_e4m3
    • --context-length 16384
    • --mem-fraction-static 0.85

部署和监控解耦推理服务器:

  1. 下载 llama3.1-405b-singlehost-a4.yaml 工作负载清单:

    curl -O https://raw.githubusercontent.com/GoogleCloudSamples/AIHypercomputerSamples/refs/heads/main/gpu/inference/llama3-405b/llama3.1-405b-singlehost-a4.yaml

    或者,创建一个名为 llama3.1-405b-singlehost-a4.yaml 的文件,其中包含以下内容:

    # ==============================================================================
    # Single-Host Disaggregated Serving of Llama 3.1 405B FP8 on GKE
    # using NVIDIA Dynamo Platform (v1.5.0) and SGLang on GPU A4 (2 x a4-highgpu-8g)
    # Topology: 1-node Prefill (8 x B200, TP=8) + 1-node Decode (8 x B200, TP=8)
    # ==============================================================================
    apiVersion: resource.k8s.io/v1
    kind: ResourceClaimTemplate
    metadata:
      name: all-mrdma
    spec:
      spec:
        devices:
          requests:
            - name: req-mrdma
              exactly:
                deviceClassName: mrdma.google.com
                allocationMode: All
    ---
    apiVersion: nvidia.com/v1alpha1
    kind: DynamoGraphDeployment
    metadata:
      name: llama3-405b-a4-disagg
      annotations:
        nvidia.com/enable-grove: "true"
    spec:
      backendFramework: sglang
      services:
        # --------------------------------------------------------------------------
        # FRONTEND: Dynamo OpenAI-Compatible Router (`python3 -m dynamo.frontend`)
        # --------------------------------------------------------------------------
        Frontend:
          componentType: frontend
          replicas: 1
          resources:
            requests:
              cpu: "8"
              memory: "32Gi"
            limits:
              cpu: "8"
              memory: "32Gi"
          extraPodSpec:
            tolerations:
              - key: "nvidia.com/gpu"
                operator: "Exists"
                effect: "NoSchedule"
            mainContainer:
              image: nvcr.io/nvidia/ai-dynamo/sglang-runtime:1.5.0
              command: ["/bin/bash", "-c"]
              args:
                - |
                  set -ex
                  exec python3 -m dynamo.frontend --http-port 8000
    
        # --------------------------------------------------------------------------
        # PREFILL WORKER: 1 x GPU A4 (`a4-highgpu-8g`, 8 x B200 GPUs, TP=8)
        # --------------------------------------------------------------------------
        Prefill:
          componentType: worker
          subComponentType: prefill
          replicas: 1
          livenessProbe:
            httpGet:
              path: /live
              port: system
            initialDelaySeconds: 600
            periodSeconds: 60
            timeoutSeconds: 30
            failureThreshold: 60
          readinessProbe:
            httpGet:
              path: /health
              port: system
            initialDelaySeconds: 120
            periodSeconds: 30
            timeoutSeconds: 30
            failureThreshold: 60
          sharedMemory:
            size: 128Gi
          resources:
            requests:
              gpu: "8"
              cpu: "128"
              memory: "1500Gi"
            limits:
              gpu: "8"
              cpu: "128"
              memory: "2000Gi"
          envs:
            - name: MODEL_PATH
              value: "nvidia/Llama-3.1-405B-Instruct-FP8"
            - name: HF_HOME
              value: "/data"
            - name: HF_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-secret
                  key: hf_api_token
                  optional: true
            - name: DYN_SYSTEM_ENABLED
              value: "true"
            - name: DYN_SYSTEM_USE_ENDPOINT_HEALTH_STATUS
              value: "[\"generate\"]"
            - name: DYN_SYSTEM_PORT
              value: "9090"
            - name: LD_LIBRARY_PATH
              value: "/usr/local/gib/lib64:/usr/local/nvidia/lib64"
            - name: GLOO_SOCKET_IFNAME
              value: "eth0"
            - name: WITH_NVIDIA_PEERMEM
              value: "0"
            # Xet CAS downloads returned unretried 429s; plain HTTP downloads back off on 429.
            - name: HF_HUB_DISABLE_XET
              value: "1"
          extraPodSpec:
            resourceClaims:
              - name: rdma
                resourceClaimTemplateName: all-mrdma
            nodeSelector:
              cloud.google.com/gke-accelerator: nvidia-b200
              cloud.google.com/gke-gpu: "true"
              kubernetes.io/arch: amd64
            tolerations:
              - key: "nvidia.com/gpu"
                operator: "Exists"
                effect: "NoSchedule"
              - key: "kubernetes.io/arch"
                operator: "Equal"
                value: "amd64"
                effect: "NoSchedule"
            mainContainer:
              image: nvcr.io/nvidia/ai-dynamo/sglang-runtime:1.5.0
              resources:
                claims:
                  - name: rdma
              startupProbe:
                httpGet:
                  path: /live
                  port: system
                initialDelaySeconds: 120
                periodSeconds: 30
                timeoutSeconds: 10
                failureThreshold: 120
              command: ["/bin/bash", "-c"]
              args:
                - |
                  set -ex
                  if [ -f /usr/local/gib/scripts/set_nccl_env.sh ]; then
                    . /usr/local/gib/scripts/set_nccl_env.sh
                  fi
    
                  # Pre-download with huggingface_hub, which backs off on HTTP 429s. Dynamo's built-in
                  # downloader (ModelExpress) aborts on the first 429 and skips fetching if weights are cached.
                  echo "=== [Dynamo Prefill Worker] Ensuring weights are cached in ${HF_HOME:-/data} ==="
                  python3 -c "import os; from huggingface_hub import snapshot_download; snapshot_download(os.environ['MODEL_PATH'], max_workers=16)"
                  # --host 0.0.0.0 is required so MooncakeKVBootstrapServer binds to 0.0.0.0:30001 instead of 127.0.0.1:30001.
                  echo "=== [Dynamo Prefill Worker] Launching dynamo.sglang ==="
                  exec python3 -m dynamo.sglang \
                    --model-path "${MODEL_PATH}" \
                    --host 0.0.0.0 \
                    --disaggregation-mode prefill \
                    --disaggregation-bootstrap-port 30001 \
                    --tensor-parallel-size 8 \
                    --kv-cache-dtype fp8_e4m3 \
                    --context-length 16384 \
                    --mem-fraction-static 0.85 \
                    --enable-metrics
              volumeMounts:
                - name: library-dir-host
                  mountPath: /usr/local/nvidia
                - name: gib
                  mountPath: /usr/local/gib
                - name: data-volume
                  mountPath: /data
            volumes:
              - name: library-dir-host
                hostPath:
                  path: /home/kubernetes/bin/nvidia
              - name: gib
                hostPath:
                  path: /home/kubernetes/bin/gib
              - name: data-volume
                emptyDir: {}
    
        # --------------------------------------------------------------------------
        # DECODE WORKER: 1 x GPU A4 (`a4-highgpu-8g`, 8 x B200 GPUs, TP=8)
        # --------------------------------------------------------------------------
        Decode:
          componentType: worker
          subComponentType: decode
          replicas: 1
          livenessProbe:
            httpGet:
              path: /live
              port: system
            initialDelaySeconds: 600
            periodSeconds: 60
            timeoutSeconds: 30
            failureThreshold: 60
          readinessProbe:
            httpGet:
              path: /health
              port: system
            initialDelaySeconds: 120
            periodSeconds: 30
            timeoutSeconds: 30
            failureThreshold: 60
          sharedMemory:
            size: 128Gi
          resources:
            requests:
              gpu: "8"
              cpu: "128"
              memory: "1500Gi"
            limits:
              gpu: "8"
              cpu: "128"
              memory: "2000Gi"
          envs:
            - name: MODEL_PATH
              value: "nvidia/Llama-3.1-405B-Instruct-FP8"
            - name: HF_HOME
              value: "/data"
            - name: HF_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-secret
                  key: hf_api_token
                  optional: true
            - name: DYN_SYSTEM_ENABLED
              value: "true"
            - name: DYN_SYSTEM_USE_ENDPOINT_HEALTH_STATUS
              value: "[\"generate\"]"
            - name: DYN_SYSTEM_PORT
              value: "9090"
            - name: LD_LIBRARY_PATH
              value: "/usr/local/gib/lib64:/usr/local/nvidia/lib64"
            - name: GLOO_SOCKET_IFNAME
              value: "eth0"
            - name: WITH_NVIDIA_PEERMEM
              value: "0"
            # Xet CAS downloads returned unretried 429s; plain HTTP downloads back off on 429.
            - name: HF_HUB_DISABLE_XET
              value: "1"
          extraPodSpec:
            resourceClaims:
              - name: rdma
                resourceClaimTemplateName: all-mrdma
            nodeSelector:
              cloud.google.com/gke-accelerator: nvidia-b200
              cloud.google.com/gke-gpu: "true"
              kubernetes.io/arch: amd64
            tolerations:
              - key: "nvidia.com/gpu"
                operator: "Exists"
                effect: "NoSchedule"
              - key: "kubernetes.io/arch"
                operator: "Equal"
                value: "amd64"
                effect: "NoSchedule"
            mainContainer:
              image: nvcr.io/nvidia/ai-dynamo/sglang-runtime:1.5.0
              resources:
                claims:
                  - name: rdma
              startupProbe:
                httpGet:
                  path: /live
                  port: system
                initialDelaySeconds: 120
                periodSeconds: 30
                timeoutSeconds: 10
                failureThreshold: 120
              command: ["/bin/bash", "-c"]
              args:
                - |
                  set -ex
                  if [ -f /usr/local/gib/scripts/set_nccl_env.sh ]; then
                    . /usr/local/gib/scripts/set_nccl_env.sh
                  fi
    
                  # Pre-download with huggingface_hub, which backs off on HTTP 429s. Dynamo's built-in
                  # downloader (ModelExpress) aborts on the first 429 and skips fetching if weights are cached.
                  echo "=== [Dynamo Decode Worker] Ensuring weights are cached in ${HF_HOME:-/data} ==="
                  python3 -c "import os; from huggingface_hub import snapshot_download; snapshot_download(os.environ['MODEL_PATH'], max_workers=16)"
                  echo "=== [Dynamo Decode Worker] Launching dynamo.sglang ==="
                  exec python3 -m dynamo.sglang \
                    --model-path "${MODEL_PATH}" \
                    --host 0.0.0.0 \
                    --disaggregation-mode decode \
                    --disaggregation-bootstrap-port 30001 \
                    --tensor-parallel-size 8 \
                    --kv-cache-dtype fp8_e4m3 \
                    --context-length 16384 \
                    --mem-fraction-static 0.85 \
                    --enable-metrics
              volumeMounts:
                - name: library-dir-host
                  mountPath: /usr/local/nvidia
                - name: gib
                  mountPath: /usr/local/gib
                - name: data-volume
                  mountPath: /data
            volumes:
              - name: library-dir-host
                hostPath:
                  path: /home/kubernetes/bin/nvidia
              - name: gib
                hostPath:
                  path: /home/kubernetes/bin/gib
              - name: data-volume
                emptyDir: {}
  2. 将工作负载清单应用到您的集群:

    kubectl apply -f llama3.1-405b-singlehost-a4.yaml
  3. 如需监控权重下载和服务器初始化,请列出集群中的 Pod,并流式传输预填充和解码 Pod 的日志:

    kubectl get pods
    POD_NAME="YOUR_POD_NAME"
    kubectl logs -f "${POD_NAME}"

    将 YOUR_POD_NAME 替换为 kubectl get pods 输出中的预填充 Pod 或解码 Pod 的名称。

    首次运行时,下载 405B FP8 模型权重并初始化 SGLang 服务器大约需要 10 到 20 分钟。在发送任何请求之前,请等待前端、预填充和解码 Pod 在 kubectl get pods 的 READY 列中显示 1/1:

    NAME                                        READY   STATUS    RESTARTS   AGE
    llama3-405b-a4-disagg-0-decode-tgl7q        1/1     Running   0          15m
    llama3-405b-a4-disagg-0-frontend-wrxq5      1/1     Running   0          15m
    llama3-405b-a4-disagg-0-prefill-67h5s       1/1     Running   0          15m
    

发送推理请求

向已部署的 Llama 3.1 405B 服务发送对话补全请求:

  1. 将本地端口 8000 转发到 llama3-405b-a4-disagg-frontend 服务:

    kubectl port-forward svc/llama3-405b-a4-disagg-frontend 8000:8000

    让端口转发在此终端会话中运行,或在后台运行该命令。

  2. 在第二个终端会话中,向 /v1/chat/completions 端点发送对话补全请求:

    curl http://127.0.0.1:8000/v1/chat/completions \
      -H "Content-Type: application/json" \
      -d '{
        "model": "nvidia/Llama-3.1-405B-Instruct-FP8",
        "messages": [{"role": "user", "content": "Explain KV-cache disaggregation in one sentence."}],
        "max_tokens": 64
      }' | jq .

运行基准工作负载

使用 sglang.bench_serving,从 Dynamo 前端 Pod 对已部署的 Llama 3.1 405B 服务器进行基准测试。将基准测试配置为 1,024 个输入词元、1,024 个输出词元 (1k/1k)、2,048 个提示和 512 个最大并发数:

ROUTER_POD=$(kubectl get pod -l 'nvidia.com/dynamo-component-type=frontend' -o jsonpath='{.items[0].metadata.name}')

kubectl exec "${ROUTER_POD}" -- python3 -m sglang.bench_serving \
  --backend sglang-oai-chat \
  --base-url http://localhost:8000 \
  --model nvidia/Llama-3.1-405B-Instruct-FP8 \
  --dataset-name random \
  --random-input-len 1024 \
  --random-output-len 1024 \
  --random-range-ratio 1.0 \
  --num-prompts 2048 \
  --max-concurrency 512 \
  --warmup-requests 10 | tee benchmark.log

基准测试完成后,查找包含如下指标的输出:

  • Output token throughput
  • Total token throughput
  • TTFT
  • TPOT

清理

为避免因本教程中使用的资源导致您的 Google Cloud 账号产生额外的持续费用,请删除 Kubernetes 工作负载、GKE 集群和 Cloud Storage 存储桶:

  1. 删除 DynamoGraphDeployment 和 ResourceClaimTemplate 资源:

    kubectl delete -f llama3.1-405b-singlehost-a4.yaml --ignore-not-found || true
  2. 卸载 NVIDIA Dynamo 平台和 KAI Scheduler Helm 版本:

    helm uninstall dynamo-platform kai-scheduler || true
  3. 删除 Hugging Face Kubernetes Secret:

    kubectl delete secret hf-secret --ignore-not-found || true
  4. 在 cluster-toolkit 目录中,使用 gcluster destroy 命令销毁 GKE 集群及其关联的基础设施:

    cd cluster-toolkit
    ./gcluster destroy "${CLUSTER_NAME}" --auto-approve || true
    cd ..
  5. 如需删除存储 Terraform 状态的 Cloud Storage 存储桶,请使用 gcloud storage rm 命令:

    gcloud storage rm --recursive "gs://${GCS_BUCKET}"

后续步骤