Entrega Llama 3.1 405B en GKE con desagregación de PD con Dynamo y SGLang en VMs A4

En este instructivo, se muestra cómo implementar y entregar Llama 3.1 405B (nvidia/Llama-3.1-405B-Instruct-FP8), un modelo ajustado por instrucciones de 405,000 millones de parámetros cuantificado a FP8, en Google Kubernetes Engine (GKE) en Google Cloud. La implementación usa Cluster Toolkit, dos instancias de máquina virtual (VM) A4 (a4-highgpu-8g) con un total de 16 GPUs NVIDIA B200, NVIDIA Dynamo y el framework de entrega de SGLang con desagregación de precompletado y decodificación (PD) de un solo host.

En la configuración de implementación que se describe en este instructivo, usarás Cluster Toolkit para aprovisionar un clúster de GKE en modo estándar. El clúster contiene dos nodos a4-highgpu-8g conectados a través de las herramientas de redes de acceso remoto directo a memoria (RDMA) de GPUDirect. Luego, instala el programador de KAI y la plataforma NVIDIA Dynamo con la programación de Grove gang. Por último, implementas un recurso personalizado de DynamoGraphDeployment que separa el prellenado y la decodificación en dos trabajadores de ocho GPU de host único con paralelismo de tensores y una caché de KV de FP8.

Objetivos

  • Instalar Cluster Toolkit y aprovisionar un clúster de GKE A4 de dos nodos en modo estándar
  • Instala el programador de KAI y la plataforma NVIDIA Dynamo con la programación de Grove gang en tu clúster.
  • Implementa un servidor de inferencia de SGLang desagregado de PD con un trabajador de precompletado de A4 de host único y un trabajador de decodificación de A4 de host único.
  • Envía una solicitud de finalización de chat al router de frontend de Dynamo.
  • Ejecuta una carga de trabajo de comparativas de entrega.
  • Limpia los recursos implementados.

Costos

En este documento, usarás los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios.

Antes de comenzar

Configura tu entorno para el instructivo:

  1. Instala e inicializa Google Cloud CLI, e instala kubectl y Helm (versión 3.10 o posterior). Si usas Cloud Shell, estas herramientas están preinstaladas.
  2. Si ejecutas este instructivo desde una estación de trabajo de Linux o macOS en lugar de Cloud Shell, instala las dependencias de Cluster Toolkit necesarias, como Terraform y Git.
  3. Habilita la API de Kubernetes Engine, la API de Compute Engine, la API de Cloud Storage, la API de Identity and Access Management, la API de Cloud Resource Manager y la API de Service Usage en tu proyecto de Google Cloud :

    Habilita las API

Obtén un token de acceso de Hugging Face

Necesitas un token de acceso de Hugging Face para usar este instructivo. Puedes registrarte para obtener una cuenta gratuita en Hugging Face. Después de tener una cuenta, genera un token de acceso:

  1. En la página Welcome to Hugging Face, haz clic en el avatar de tu cuenta y selecciona Tokens de acceso.
  2. En la página Tokens de acceso, haz clic en Crear token nuevo.
  3. Selecciona el tipo de token Lectura y, luego, ingresa un nombre para el token.
  4. Se mostrará tu token de acceso. Guarda el token en un lugar seguro.

Roles obligatorios

Si quieres obtener los permisos que necesitas para completar este instructivo, pídele a tu administrador que te otorgue los siguientes roles de IAM en tu proyecto:

Para obtener más información sobre cómo otorgar roles, consulta Administra el acceso a proyectos, carpetas y organizaciones.

También puedes obtener los permisos necesarios a través de roles personalizados o cualquier otro rol predefinido.

Configura tus variables de entorno

Exporta las variables de entorno que usarás en este instructivo:

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}"

Reemplaza lo siguiente:

  • YOUR_PROJECT_ID: Es el ID de tu proyecto de Google Cloud.
  • YOUR_REGION: Es la región en la que se encuentra tu capacidad de A4 y en la que deseas implementar tu clúster, como us-central1.
  • YOUR_ZONE: Es la zona en la que se encuentra tu capacidad de A4, como us-central1-b.
  • YOUR_CLUSTER_NAME: Es el nombre de tu clúster de GKE y de la implementación de Cluster Toolkit. Usa un nombre de 20 caracteres o menos para que el ID de cuenta de servicio del grupo de nodos generado (YOUR_CLUSTER_NAME-gke-np-sa) se mantenga dentro del límite de 30 caracteres de Identity and Access Management (IAM).
  • YOUR_RESERVATION_NAME: Es el nombre de tu reserva de A4.
  • YOUR_BUCKET_NAME: un nombre único a nivel global para el bucket de Cloud Storage que almacena el estado de Terraform para Cluster Toolkit.
  • YOUR_HF_TOKEN: Es tu token de acceso de Hugging Face.

Crea el clúster de GKE

Descarga Cluster Toolkit y aprovisiona un clúster de GKE en modo estándar con dos nodos a4-highgpu-8g, redes de RDMA de GPUDirect y compatibilidad con DRA:

  1. Accede a Google Cloud CLI y genera credenciales predeterminadas de la aplicación para Terraform:

    gcloud auth login
    gcloud auth application-default login
  2. Descarga y extrae el paquete de Cluster Toolkit compilado previamente para la versión especificada en CLUSTER_TOOLKIT_VERSION (v1.104.0):

    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

    Si ejecutas este comando en macOS o en una estación de trabajo arm64, configura OS="mac" o ARCH="arm64" para que coincida con tu plataforma.

  3. Para almacenar el estado de Terraform de tu implementación de Cluster Toolkit, crea un bucket de Cloud Storage con el control de versiones de objetos habilitado:

    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. Crea el archivo de configuración de implementación cluster-toolkit/examples/gke-a4/gke-a4-deployment.yaml para dos nodos a4-highgpu-8g:

    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

    De forma predeterminada, el archivo de implementación está configurado para consumir una reserva específica. Si no tienes una reserva específica, antes de implementar el clúster, puedes actualizar cluster-toolkit/examples/gke-a4/gke-a4-deployment.yaml para usar una opción de consumo alternativa, como VMs Spot o VMs de inicio flexible. Para obtener instrucciones de configuración, consulta Opciones de consumo de GKE.

  5. Cambia al directorio cluster-toolkit, implementa el clúster de GKE con el comando gcluster deploy y, luego, regresa a tu directorio de trabajo:

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

    La creación de clústeres tarda entre 20 y 30 minutos aproximadamente. Si ejecutas ./gcluster deploy sin la marca --auto-approve, para aplicar los cambios propuestos, ingresa a cuando se te solicite.

  6. Configura las credenciales de kubectl para comunicarte con tu clúster:

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

Instala KAI Scheduler y NVIDIA Dynamo

Prepara tu clúster creando un Secret de Hugging Face y, luego, instalando el programador de KAI y la plataforma NVIDIA Dynamo con la programación de Grove Gang:

  1. Crea un Secret de Kubernetes llamado hf-secret para almacenar tu token de acceso de Hugging Face:

    kubectl create secret generic hf-secret \
        --from-literal=hf_api_token="${HF_TOKEN}" \
        --dry-run=client -o yaml | kubectl apply -f -
  2. Descarga el gráfico de Helm de la plataforma NVIDIA Dynamo (v1.5.0), instala el programador de KAI y, luego, instala la plataforma Dynamo con Grove habilitado:

    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

Implementa el servidor de SGLang desagregado de host único

El manifiesto de la carga de trabajo (llama3.1-405b-singlehost-a4.yaml) define un ResourceClaimTemplate de Kubernetes (all-mrdma), que asigna los dispositivos RDMA multi-NIC del nodo (mrdma.google.com) a través de DRA, y un DynamoGraphDeployment de NVIDIA Dynamo (llama3-405b-a4-disagg) con la programación de grupos de Grove habilitada. La implementación consiste en lo siguiente:

  • Frontend (Frontend): Ejecuta una réplica de router que acepta solicitudes de clientes, descubre trabajadores de precompletado y decodificación registrados, y coordina el enrutamiento de solicitudes desagregadas.
  • Trabajador de precompletado (Prefill): Ejecuta un trabajador de host único en un nodo a4-highgpu-8g con ocho GPUs NVIDIA B200. Cuando se inicia, el Pod obtiene el entorno de NCCL/gIB, descarga el punto de control nvidia/Llama-3.1-405B-Instruct-FP8 de Hugging Face Hub en la SSD de NVMe local del nodo y, luego, inicia python3 -m dynamo.sglang en --disaggregation-mode prefill con las siguientes marcas:
    • --tensor-parallel-size 8
    • --kv-cache-dtype fp8_e4m3
    • --context-length 16384
    • --mem-fraction-static 0.85
  • Trabajador de decodificación (Decode): Ejecuta un trabajador de un solo host en el segundo nodo a4-highgpu-8g con ocho GPU NVIDIA B200. Durante el inicio, el Pod almacena en caché los pesos del modelo en la SSD de NVMe local del nodo y, luego, inicia python3 -m dynamo.sglang en --disaggregation-mode decode con las siguientes marcas:
    • --tensor-parallel-size 8
    • --kv-cache-dtype fp8_e4m3
    • --context-length 16384
    • --mem-fraction-static 0.85

Implementa y supervisa el servidor de inferencia desagregado:

  1. Descarga el manifiesto de la carga de trabajo de 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

    Como alternativa, crea un archivo llamado llama3.1-405b-singlehost-a4.yaml con el siguiente contenido:

    # ==============================================================================
    # 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. Aplica el manifiesto de la carga de trabajo a tu clúster:

    kubectl apply -f llama3.1-405b-singlehost-a4.yaml
  3. Para supervisar la descarga de pesos y la inicialización del servidor, enumera los Pods en tu clúster y transmite los registros de los Pods de precompletado y decodificación:

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

    Reemplaza YOUR_POD_NAME por el nombre del Pod de precompletado o el Pod de decodificación del resultado de kubectl get pods.

    En la primera ejecución, se tarda aproximadamente entre 10 y 20 minutos en descargar los pesos del modelo FP8 de 405B y, luego, inicializar los servidores de SGLang. Antes de enviar cualquier solicitud, espera hasta que los Pods de frontend, prefill y decode muestren 1/1 en la columna READY de kubectl get pods:

    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
    

Envía solicitudes de inferencia

Envía una solicitud de finalización de chat al servicio de Llama 3.1 405B implementado:

  1. Redirecciona el puerto local 8000 al servicio llama3-405b-a4-disagg-frontend:

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

    Deja la redirección de puertos en ejecución en esta sesión de terminal o ejecuta el comando en segundo plano.

  2. En una segunda sesión de terminal, envía una solicitud de finalización de chat al extremo /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 .

Ejecuta una carga de trabajo de comparativas

Compara el servidor de Llama 3.1 405B implementado desde el Pod de frontend de Dynamo con sglang.bench_serving. Configura la comparativa para 1,024 tokens de entrada, 1,024 tokens de salida (1k/1k), 2,048 instrucciones y una simultaneidad máxima de 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

Una vez que se complete la comparativa, busca un resultado que contenga métricas como las siguientes:

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

Realiza una limpieza

Para evitar que se apliquen cargos adicionales continuos a tu cuenta de Google Cloud por los recursos que usaste en este instructivo, borra las cargas de trabajo de Kubernetes, el clúster de GKE y el bucket de Cloud Storage:

  1. Borra los recursos DynamoGraphDeployment y ResourceClaimTemplate:

    kubectl delete -f llama3.1-405b-singlehost-a4.yaml --ignore-not-found || true
  2. Desinstala las versiones de Helm de la plataforma NVIDIA Dynamo y KAI Scheduler:

    helm uninstall dynamo-platform kai-scheduler || true
  3. Borra el Secret de Kubernetes de Hugging Face:

    kubectl delete secret hf-secret --ignore-not-found || true
  4. En el directorio cluster-toolkit, destruye el clúster de GKE y su infraestructura asociada con el comando gcluster destroy:

    cd cluster-toolkit
    ./gcluster destroy "${CLUSTER_NAME}" --auto-approve || true
    cd ..
  5. Para borrar el bucket de Cloud Storage que almacena el estado de Terraform, usa el comando gcloud storage rm:

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

¿Qué sigue?