Diffuser Llama 3.1 405B sur GKE avec désagrégation des disques persistants à l'aide de Dynamo et SGLang sur des VM A4

Ce tutoriel vous explique comment déployer et diffuser Llama 3.1 405B (nvidia/Llama-3.1-405B-Instruct-FP8), un modèle de 405 milliards de paramètres ajusté aux instructions et quantifié en FP8, sur Google Kubernetes Engine (GKE) sur Google Cloud. Le déploiement utilise Cluster Toolkit, deux instances de machines virtuelles (VM) A4 (a4-highgpu-8g) avec un total de 16 GPU NVIDIA B200, NVIDIA Dynamo et le framework de diffusion SGLang avec désagrégation de préremplissage/décodage (PD) sur un seul hôte.

Dans la configuration de déploiement décrite dans ce tutoriel, vous allez utiliser Cluster Toolkit pour provisionner un cluster GKE en mode Standard. Le cluster contient deux nœuds a4-highgpu-8g connectés via un réseau d'accès direct à la mémoire à distance (RDMA) GPUDirect. Vous installerez ensuite le planificateur KAI et la plate-forme NVIDIA Dynamo avec la planification de groupe Grove. Enfin, vous déployez une ressource personnalisée DynamoGraphDeployment qui sépare le préremplissage et le décodage sur deux nœuds de calcul à hôte unique et huit GPU avec parallélisme de tenseur et un cache KV FP8.

Objectifs

  • Installez Cluster Toolkit et provisionnez un cluster GKE A4 à deux nœuds en mode Standard.
  • Installez le planificateur KAI et la plate-forme NVIDIA Dynamo avec la planification de groupe Grove sur votre cluster.
  • Déployez un serveur d'inférence SGLang désagrégé par PD avec un nœud de calcul de préremplissage A4 à hôte unique et un nœud de calcul de décodage A4 à hôte unique.
  • Envoyez une requête de complétion de chat au routeur d'interface Dynamo.
  • Exécutez une charge de travail de benchmark de diffusion.
  • Nettoyez les ressources déployées.

Coûts

Dans ce document, vous utilisez les composants facturables suivants deGoogle Cloud :

Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût.

Avant de commencer

Configurez votre environnement pour le tutoriel :

  1. Installez et initialisez la Google Cloud CLI, puis installez kubectl et Helm (version 3.10 ou ultérieure). Si vous utilisez Cloud Shell, ces outils sont préinstallés.
  2. Si vous suivez ce tutoriel depuis un poste de travail Linux ou macOS plutôt que depuis Cloud Shell, installez les dépendances Cluster Toolkit requises, telles que Terraform et Git.
  3. Activez l'API Kubernetes Engine, l'API Compute Engine, l'API Cloud Storage, l'API Identity and Access Management, l'API Cloud Resource Manager et l'API Service Usage dans votre projet Google Cloud  :

    Activer les API

Obtenir un jeton d'accès Hugging Face

Vous avez besoin d'un jeton d'accès Hugging Face pour suivre ce tutoriel. Vous pouvez créer un compte sans frais sur Hugging Face. Une fois que vous disposez d'un compte, générez un jeton d'accès :

  1. Sur la page Welcome to Hugging Face (Bienvenue sur Hugging Face), cliquez sur l'avatar de votre compte, puis sélectionnez Access tokens (Jetons d'accès).
  2. Sur la page Access tokens (Jetons d'accès), cliquez sur Create new token (Créer un jeton).
  3. Sélectionnez le type de jeton Read (Lecture) et saisissez un nom pour votre jeton.
  4. Votre jeton d'accès s'affiche. Enregistrez le jeton dans un endroit sûr.

Rôles requis

Pour obtenir les autorisations nécessaires pour suivre ce tutoriel, demandez à votre administrateur de vous accorder les rôles IAM suivants sur votre projet :

Pour en savoir plus sur l'attribution de rôles, consultez la page Gérer l'accès aux projets, aux dossiers et aux organisations.

Vous pouvez également obtenir les autorisations requises avec des rôles personnalisés ou d'autres rôles prédéfinis.

Configurer vos variables d'environnement

Exportez les variables d'environnement que vous utiliserez tout au long de ce tutoriel :

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

Remplacez les éléments suivants :

  • YOUR_PROJECT_ID : ID de votre projet Google Cloud.
  • YOUR_REGION : région où se trouve votre capacité A4 et où vous souhaitez déployer votre cluster, par exemple us-central1.
  • YOUR_ZONE : zone où se trouve votre capacité A4, par exemple us-central1-b.
  • YOUR_CLUSTER_NAME : nom de votre cluster GKE et de votre déploiement Cluster Toolkit. Utilisez un nom de 20 caractères ou moins pour que l'ID de compte de service du pool de nœuds généré (YOUR_CLUSTER_NAME-gke-np-sa) ne dépasse pas la limite de 30 caractères d'Identity and Access Management (IAM).
  • YOUR_RESERVATION_NAME : nom de votre réservation A4.
  • YOUR_BUCKET_NAME : nom unique du bucket Cloud Storage qui stocke l'état Terraform pour Cluster Toolkit.
  • YOUR_HF_TOKEN : votre jeton d'accès Hugging Face.

Créer le cluster GKE

Téléchargez Cluster Toolkit et provisionnez un cluster GKE en mode Standard avec deux nœuds a4-highgpu-8g, une mise en réseau GPUDirect RDMA et la compatibilité DRA :

  1. Connectez-vous à la Google Cloud CLI et générez des identifiants par défaut de l'application pour Terraform :

    gcloud auth login
    gcloud auth application-default login
  2. Téléchargez et extrayez le bundle Cluster Toolkit prédéfini pour la version spécifiée dans 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 vous exécutez cette commande sur macOS ou sur un poste de travail arm64, définissez OS="mac" ou ARCH="arm64" pour qu'il corresponde à votre plate-forme.

  3. Pour stocker l'état Terraform de votre déploiement Cluster Toolkit, créez un bucket Cloud Storage avec la gestion des versions d'objets activée :

    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. Créez le fichier de configuration de déploiement cluster-toolkit/examples/gke-a4/gke-a4-deployment.yaml pour deux nœuds 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

    Par défaut, le fichier de déploiement est configuré pour utiliser une réservation spécifique. Si vous n'avez pas de réservation spécifique, vous pouvez mettre à jour cluster-toolkit/examples/gke-a4/gke-a4-deployment.yaml avant de déployer le cluster pour utiliser une autre option de consommation, telle que les VM Spot ou les VM Flex-start. Pour obtenir des instructions de configuration, consultez Options de consommation GKE.

  5. Accédez au répertoire cluster-toolkit, déployez le cluster GKE à l'aide de la commande gcluster deploy, puis revenez à votre répertoire de travail :

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

    La création du cluster prend environ 20 à 30 minutes. Si vous exécutez ./gcluster deploy sans l'option --auto-approve, saisissez a lorsque vous y êtes invité pour appliquer les modifications proposées.

  6. Configurez les identifiants kubectl pour communiquer avec votre cluster :

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

Installer le planificateur KAI et NVIDIA Dynamo

Préparez votre cluster en créant un secret Hugging Face et en installant le planificateur KAI et la plate-forme NVIDIA Dynamo avec la planification de groupe Grove :

  1. Créez un secret Kubernetes nommé hf-secret pour stocker votre jeton d'accès Hugging Face :

    kubectl create secret generic hf-secret \
        --from-literal=hf_api_token="${HF_TOKEN}" \
        --dry-run=client -o yaml | kubectl apply -f -
  2. Téléchargez le chart Helm de la plate-forme NVIDIA Dynamo (v1.5.0), installez le planificateur KAI, puis installez la plate-forme Dynamo avec Grove activé :

    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

Déployer le serveur SGLang désagrégé à hôte unique

Le fichier manifeste de la charge de travail (llama3.1-405b-singlehost-a4.yaml) définit un ResourceClaimTemplate Kubernetes (all-mrdma), qui alloue les appareils RDMA multi-NIC du nœud (mrdma.google.com) via DRA, et un DynamoGraphDeployment NVIDIA Dynamo (llama3-405b-a4-disagg) avec la planification de groupe Grove activée. Le déploiement comprend les éléments suivants :

  • Interface (Frontend) : exécute une instance répliquée de routeur qui accepte les requêtes des clients, découvre les nœuds de calcul de préremplissage et de décodage enregistrés, et coordonne le routage des requêtes désagrégées.
  • Nœud de calcul de préremplissage (Prefill) : exécute un nœud de calcul à hôte unique sur un nœud a4-highgpu-8g avec huit GPU NVIDIA B200. Au démarrage, le pod source l'environnement NCCL/gIB, télécharge le point de contrôle nvidia/Llama-3.1-405B-Instruct-FP8 depuis Hugging Face Hub vers le disque SSD NVMe local du nœud, puis lance python3 -m dynamo.sglang dans --disaggregation-mode prefill avec les options suivantes :
    • --tensor-parallel-size 8
    • --kv-cache-dtype fp8_e4m3
    • --context-length 16384
    • --mem-fraction-static 0.85
  • Nœud de calcul de décodage (Decode) : exécute un nœud de calcul à hôte unique sur le deuxième nœud a4-highgpu-8g avec huit GPU NVIDIA B200. Au démarrage, le pod met en cache les pondérations du modèle sur le disque SSD NVMe local du nœud et lance python3 -m dynamo.sglang dans --disaggregation-mode decode avec les options suivantes :
    • --tensor-parallel-size 8
    • --kv-cache-dtype fp8_e4m3
    • --context-length 16384
    • --mem-fraction-static 0.85

Déployez et surveillez le serveur d'inférence désagrégé :

  1. Téléchargez le fichier manifeste de la charge de travail 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

    Vous pouvez également créer un fichier nommé llama3.1-405b-singlehost-a4.yaml avec le contenu suivant :

    # ==============================================================================
    # 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. Appliquez le fichier manifeste de la charge de travail à votre cluster :

    kubectl apply -f llama3.1-405b-singlehost-a4.yaml
  3. Pour surveiller le téléchargement des pondérations et l'initialisation du serveur, listez les pods de votre cluster et diffusez les journaux des pods de préremplissage et de décodage :

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

    Remplacez YOUR_POD_NAME par le nom du pod de préremplissage ou du pod de décodage de la sortie kubectl get pods.

    Lors de la première exécution, le téléchargement des pondérations du modèle 405B FP8 et l'initialisation des serveurs SGLang prennent environ 10 à 20 minutes. Avant d'envoyer des requêtes, attendez que les pods d'interface, de préremplissage et de décodage affichent 1/1 dans la colonne 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
    

Envoyer des requêtes d'inférence

Envoyez une requête de complétion de chat au service Llama 3.1 405B déployé :

  1. Transférez le port local 8000 vers le service llama3-405b-a4-disagg-frontend :

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

    Laissez le transfert de port s'exécuter dans cette session de terminal ou exécutez la commande en arrière-plan.

  2. Dans une deuxième session de terminal, envoyez une requête de complétion de chat au point de terminaison /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 .

Exécuter une charge de travail de benchmark

Effectuez une analyse comparative du serveur Llama 3.1 405B déployé à partir du pod d'interface Dynamo à l'aide de sglang.bench_serving. Configurez le benchmark pour 1 024 jetons d'entrée, 1 024 jetons de sortie (1k/1k), 2 048 requêtes et une simultanéité maximale 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

Une fois l'analyse comparative terminée, recherchez un résultat contenant des métriques telles que les suivantes :

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

Effectuer un nettoyage

Pour éviter que des frais supplémentaires ne soient facturés sur votre compte Google Cloud pour les ressources utilisées dans ce tutoriel, supprimez les charges de travail Kubernetes, le cluster GKE et votre bucket Cloud Storage :

  1. Supprimez les ressources DynamoGraphDeployment et ResourceClaimTemplate :

    kubectl delete -f llama3.1-405b-singlehost-a4.yaml --ignore-not-found || true
  2. Désinstallez les versions Helm de la plate-forme NVIDIA Dynamo et du planificateur KAI :

    helm uninstall dynamo-platform kai-scheduler || true
  3. Supprimez le secret Kubernetes Hugging Face :

    kubectl delete secret hf-secret --ignore-not-found || true
  4. À partir du répertoire cluster-toolkit, détruisez le cluster GKE et l'infrastructure associée à l'aide de la commande gcluster destroy :

    cd cluster-toolkit
    ./gcluster destroy "${CLUSTER_NAME}" --auto-approve || true
    cd ..
  5. Pour supprimer le bucket Cloud Storage qui stocke l'état Terraform, utilisez la commande gcloud storage rm :

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

Étapes suivantes