Scalabilità automatica dell'erogazione dei modelli vLLM con le metriche GPU

Questo tutorial descrive come eseguire la scalabilità automatica dei servizi Cloud Run che pubblicano LLM con vLLM in base alle metriche GPU personalizzate utilizzando la scalabilità automatica delle metriche esterne di Cloud Run (CREMA).

Sebbene Cloud Run esegua la scalabilità automatica utilizzando l'utilizzo della CPU e la concorrenza per impostazione predefinita, i carichi di lavoro di inferenza che richiedono un utilizzo intensivo della GPU spesso richiedono la scalabilità automatica in base alle metriche della coda, come il numero di richieste in esecuzione o l'utilizzo della cache KV. CREMA integra la scalabilità automatica basata su eventi (KEDA) basata su Kubernetes con Cloud Run per abilitare la scalabilità dinamica basata sulle metriche di Prometheus. vLLM espone le metriche di Prometheus e le invia a Cloud Monitoring.

Obiettivi

In questo tutorial, imparerai a:

Costi

In questo documento vengono utilizzati i seguenti componenti fatturabili di Google Cloud:

Per generare una stima dei costi in base all'utilizzo previsto, utilizza il calcolatore prezzi.

I nuovi Google Cloud utenti potrebbero avere diritto a una prova senza costi.

Prima di iniziare

  1. Accedi al tuo Google Cloud account. Se non conosci Google Cloud, crea un account per valutare le prestazioni dei nostri prodotti in scenari reali. I nuovi clienti ricevono anche 300 $di crediti senza costi per l'esecuzione, il test e il deployment dei carichi di lavoro.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  5. Verify that billing is enabled for your Google Cloud project.

  6. Abilita le API Cloud Run, Parameter Manager, Artifact Registry, Cloud Build, Secret Manager e Cloud Monitoring.

    Ruoli richiesti per abilitare le API

    Per abilitare le API, devi disporre dell'autorizzazione serviceusage.services.enable. Se hai creato il progetto, probabilmente hai già questa autorizzazione tramite il ruolo Proprietario (roles/owner). In caso contrario, puoi ottenere questa autorizzazione tramite il ruolo Amministratore utilizzo servizi (roles/serviceusage.serviceUsageAdmin). Scopri come concedere i ruoli.

    Abilita le API

  7. Installa e inizializza gcloud CLI.
  8. Imposta le variabili di ambiente utilizzate in questo tutorial:
    export PROJECT_ID=PROJECT_ID
    export REGION=us-central1
    export VLLM_SERVICE_NAME=vllm-service
    export MODEL_NAME=gemma-2-2b-it
    export REPO_NAME=vllm-repo
    export BUCKET_NAME=my-vllm-models-${PROJECT_ID}
    export CREMA_SERVICE_NAME=crema-service
    Sostituisci PROJECT_ID con l'ID Google Cloud progetto.
  9. Imposta la configurazione del progetto:
    gcloud config set project $PROJECT_ID
  10. Se non ne hai già uno, crea un account su Hugging Face. Quindi, crea un token di lettura sul sito di Hugging Face. Hugging Face mostra il token una sola volta. Salvalo in una posizione sicura, non potrai visualizzarlo di nuovo.
  11. Vai alla pagina del modello gemma-2-2b-it su Hugging Face e accetta i termini di contratto del modello.

Ruoli obbligatori

Per ottenere le autorizzazioni necessarie per completare il tutorial, chiedi all'amministratore di concederti i seguenti ruoli IAM nel progetto:

Per saperne di più sulla concessione dei ruoli, consulta Gestisci l'accesso a progetti, cartelle e organizzazioni.

Potresti anche riuscire a ottenere le autorizzazioni richieste tramite i ruoli personalizzati o altri ruoli predefiniti.

Scaricare e caricare i pesi del modello in Cloud Storage

Scarica i pesi del modello da Hugging Face e trasferiscili in un bucket Cloud Storage per renderli disponibili per l'erogazione del modello:

  1. Installa l'interfaccia a riga di comando di Hugging Face:

    pip install -U "huggingface_hub[cli]"
    
  2. Scarica i pesi del modello localmente utilizzando l'interfaccia a riga di comando di Hugging Face:

    export HF_TOKEN="HF_TOKEN"
    export LOCAL_DIR="/tmp/$MODEL_NAME"
    HF_HOME=/tmp/huggingface python -m huggingface_hub.cli.hf download google/$MODEL_NAME --token $HF_TOKEN --local-dir=$LOCAL_DIR
    

    Sostituisci HF_TOKEN con il token di accesso utente di Hugging Face. Il token deve iniziare con hf_ seguito da 35 caratteri alfanumerici casuali (ad esempio, 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).

  3. Crea un bucket Cloud Storage e copia i pesi scaricati:

    gcloud storage buckets create gs://$BUCKET_NAME \
        --project=$PROJECT_ID \
        --location=$REGION \
        --uniform-bucket-level-access
    
    gcloud storage cp -r $LOCAL_DIR gs://$BUCKET_NAME/
    

Eseguire il push dell'immagine container vLLM in Artifact Registry

Esegui il pull delle immagini container di erogazione del modello e il push in un repository in Artifact Registry:

  1. Crea un repository Docker in Artifact Registry:

    gcloud artifacts repositories create $REPO_NAME \
        --repository-format=docker \
        --location=$REGION \
        --description="vLLM Docker Images"
    
  2. Autentica il daemon Docker locale con il registro:

    gcloud auth configure-docker ${REGION}-docker.pkg.dev
    
  3. Esegui il pull dell'immagine vLLM, taggala ed esegui il push in Artifact Registry:

    docker pull docker.io/vllm/vllm-openai:latest
    docker tag docker.io/vllm/vllm-openai:latest ${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/vllm-openai:latest
    docker push ${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/vllm-openai:latest
    

Eseguire il deployment del servizio di scalabilità automatica CREMA

Configura i ruoli degli account di servizio e i manifest dei parametri per CREMA prima di eseguire il deployment del servizio di scalabilità automatica.

Crea un account di servizio personalizzato

Crea un account di servizio personalizzato con le autorizzazioni minime richieste per utilizzare le risorse di cui è stato eseguito il provisioning. Questo account di servizio funge da identità per la scalabilità automatica. Esegui il comando seguente per creare l'account di servizio CREMA:

export CREMA_SA="crema-autoscaler@${PROJECT_ID}.iam.gserviceaccount.com"

gcloud iam service-accounts create crema-autoscaler \
    --description="Service account for Cloud Run CREMA to read metrics and scale workloads" \
    --display-name="CREMA Autoscaler System"

Concedi autorizzazioni aggiuntive al tuo account di servizio personalizzato

Per scalare il servizio, concedi le seguenti autorizzazioni all'account di servizio personalizzato:

  1. Concedi al tuo account di servizio CREMA l'autorizzazione per leggere da Parameter Manager:

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/parametermanager.parameterViewer"
    
  2. Concedi al tuo account di servizio CREMA l'autorizzazione per scalare il servizio:

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/run.developer"
    
  3. Concedi al tuo account di servizio CREMA il ruolo Utente account di servizio:

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/iam.serviceAccountUser"
    
  4. Concedi al tuo account di servizio CREMA l'autorizzazione per visualizzare le metriche:

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/monitoring.viewer"
    

Crea e registra la configurazione CREMA

Definisci le soglie e le regole di scalabilità in un manifest di configurazione CREMA e registralo in Parameter Manager:

  1. Salva la seguente configurazione come my-crema-config.yaml. Questa configurazione attiva la scalabilità quando il numero di richieste in esecuzione (vllm:num_requests_running) supera 2:

    apiVersion: crema/v1
    kind: CremaConfig
    spec:
      pollingInterval: 15
      triggerAuthentications:
        - metadata:
            name: adc-trigger-auth
          spec:
            podIdentity:
              provider: gcp
      scaledObjects:
        - spec:
            scaleTargetRef:
              name: projects/PROJECT_ID/locations/us-central1/services/vllm-service
            minReplicaCount: 1
            maxReplicaCount: 5
            triggers:
              - type: prometheus
                authenticationRef:
                  name: adc-trigger-auth
                metadata:
                  serverAddress: https://monitoring.googleapis.com/v1/projects/PROJECT_ID/location/global/prometheus
                  metric: vllm:num_requests_running
                  query: sum(vllm:num_requests_running)
                  threshold: '2'
    
  2. Registra il file di configurazione in Parameter Manager:

    gcloud parametermanager parameters create crema-config \
        --location=global \
        --parameter-format=YAML
    
    gcloud parametermanager parameters versions create 1 \
        --location=global \
        --parameter=crema-config \
        --payload-data-from-file=my-crema-config.yaml
    

Esegui il deployment del servizio CREMA

Esegui il deployment dell'immagine CREMA come servizio in background interno su Cloud Run:

gcloud run deploy $CREMA_SERVICE_NAME \
    --image=us-central1-docker.pkg.dev/cloud-run-oss-images/crema-v1/autoscaler:1.0 \
    --region=$REGION \
    --service-account="$CREMA_SA" \
    --no-allow-unauthenticated \
    --no-cpu-throttling \
    --cpu=1 \
    --memory=1Gi \
    --min-instances=1 \
    --max-instances=1 \
    --ingress=internal \
    --base-image=us-central1-docker.pkg.dev/serverless-runtimes/google-24/runtimes/java25 \
    --set-env-vars="CREMA_CONFIG=projects/$PROJECT_ID/locations/global/parameters/crema-config/versions/1,OUTPUT_SCALER_METRICS=True"

Configurare le autorizzazioni del servizio vLLM

Concedi all'account di servizio predefinito di Compute Engine le autorizzazioni per esportare le metriche e leggere i pesi del modello da Cloud Storage:

  1. Recupera il numero del progetto:

    export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
    
  2. Concedi al tuo account di servizio l'autorizzazione per scrivere le metriche:

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
        --role="roles/monitoring.metricWriter"
    
  3. Concedi al tuo account di servizio l'autorizzazione per leggere i pesi del modello da Cloud Storage:

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
        --role="roles/storage.objectViewer"
    

Eseguire il deployment del servizio vLLM con il sidecar OpenTelemetry

Esegui il deployment del container di pubblicazione vLLM principale su Cloud Run con i pesi del modello montati da Cloud Storage. Poiché il deployment di servizi multi-container con sidecar su Cloud Run richiede una specifica di servizio YAML dichiarativa, configura il motore vLLM principale insieme a un agente di raccolta sidecar OpenTelemetry per eseguire lo scraping ed esportare le metriche vLLM:

  1. Salva la seguente specifica di deployment multi-container come vllm-service.yaml:

    apiVersion: serving.knative.dev/v1
    kind: Service
    metadata:
      name: vllm-service
      labels:
        cloud.googleapis.com/location: us-central1
      annotations:
        run.googleapis.com/scalingMode: manual
        run.googleapis.com/manualInstanceCount: "1"
    spec:
      template:
        metadata:
          annotations:
            run.googleapis.com/execution-environment: gen2
            run.googleapis.com/cpu-throttling: "false"
            run.googleapis.com/gpu-zonal-redundancy-disabled: "true"
            autoscaling.knative.dev/minScale: "1"
        spec:
          containerConcurrency: 80
          nodeSelector:
            run.googleapis.com/accelerator: nvidia-l4
          volumes:
            - name: gcs-volume
              csi:
                driver: gcsfuse.run.googleapis.com
                volumeAttributes:
                  bucketName: my-vllm-models-PROJECT_ID
          containers:
            # Primary container: vLLM serving engine
            - name: vllm-container
              image: us-central1-docker.pkg.dev/PROJECT_ID/vllm-repo/vllm-openai:latest
              ports:
                - containerPort: 8080
              resources:
                limits:
                  cpu: "4"
                  memory: 16Gi
                  nvidia.com/gpu: "1"
              args:
                - "--model"
                - "/gcs/gemma-2-2b-it"
                - "--port"
                - "8080"
                - "--max-model-len"
                - "2048"
                - "--chat-template"
                - "{% for msg in messages %}{{ msg['content'] }}{% endfor %}"
              volumeMounts:
                - name: gcs-volume
                  mountPath: /gcs
              startupProbe:
                httpGet:
                  path: /health
                  port: 8080
                periodSeconds: 10
                failureThreshold: 24
    
            # Sidecar container: OpenTelemetry Collector
            - name: otel-collector
              image: otel/opentelemetry-collector-contrib:latest
              resources:
                limits:
                  cpu: "1"
                  memory: 1Gi
              args:
                - |
                  --config=yaml:
                  receivers:
                    prometheus:
                      config:
                        scrape_configs:
                          - job_name: 'vllm'
                            scrape_interval: 10s
                            metrics_path: '/metrics'
                            static_configs:
                              - targets: ['localhost:8080']
                  processors:
                    resourcedetection:
                      detectors: [gcp]
                      timeout: 2s
                    transform:
                      metric_statements:
                        - context: datapoint
                          statements:
                            - set(attributes["exported_location"], attributes["location"])
                            - delete_key(attributes, "location")
                            - set(attributes["exported_cluster"], attributes["cluster"])
                            - delete_key(attributes, "cluster")
                            - set(attributes["exported_namespace"], attributes["namespace"])
                            - delete_key(attributes, "namespace")
                            - set(attributes["exported_job"], attributes["job"])
                            - delete_key(attributes, "job")
                            - set(attributes["exported_instance"], attributes["instance"])
                            - delete_key(attributes, "instance")
                  exporters:
                    googlemanagedprometheus:
                  service:
                    pipelines:
                      metrics:
                        receivers: [prometheus]
                        processors: [resourcedetection, transform]
                        exporters: [googlemanagedprometheus]
    
  2. Sostituisci la configurazione del servizio esistente con il manifest multi-container:

    gcloud run services replace vllm-service.yaml
    

Controllare i log del servizio CREMA

  1. Nella Google Cloud console, vai alla pagina Cloud Run.
  2. Seleziona crema-service.
  3. Fai clic sulla scheda Log e verifica che i cicli di polling delle metriche siano attivi:

    [INFO] [METRIC-PROVIDER] Starting metric collection cycle
    [INFO] [METRIC-PROVIDER] Successfully fetched scaled object metrics ...
    [INFO] [METRIC-PROVIDER] Sending scale request ...
    [INFO] [SCALER] Received ScaleRequest ...
    [INFO] [SCALER] Current instances ...
    [INFO] [SCALER] Recommended instances ...
    

Eseguire un test di carico

Per testare la scalabilità automatica, esegui uno script di test di carico per inviare richieste simultanee al servizio vLLM:

  1. Nella directory di lavoro, crea un file denominato load-test.sh e aggiungi il seguente codice:

    #!/bin/bash
    
    export SERVICE_URL=$(gcloud run services describe $VLLM_SERVICE_NAME --region $REGION --format='value(status.url)')
    
    echo "Launching 5 parallel heavy requests to trigger autoscaling..."
    
    for i in {1..5}; do
        curl -s -X POST "${SERVICE_URL}/v1/chat/completions" \
            -H "Authorization: Bearer $(gcloud auth print-identity-token)" \
            -H "Content-Type: application/json" \
            -d "{
                \"model\": \"/gcs/${MODEL_NAME}\",
                \"messages\": [{\"role\": \"user\", \"content\": \"Write an exceptionally long, detailed, and exhaustive essay about the entire history of the universe from the Big Bang to the modern day.\"}]
            }" > /dev/null &
    done
    
    echo "All 5 requests dispatched. Waiting for requests to complete..."
    wait
    echo "Done."
    
  2. Rendi eseguibile lo script ed esegui il test di carico:

    chmod +x load-test.sh
    ./load-test.sh
    
  3. Controlla di nuovo i log di crema-service e la dashboard delle metriche di Cloud Run per verificare che il numero di istanze consigliato aumenti in risposta alle richieste in coda.

Esplorare le metriche vLLM in Cloud Monitoring

Dopo aver eseguito il test di carico, esplora in che modo il traffico influisce sulle metriche di erogazione del modello in Cloud Monitoring:

  1. Nella Google Cloud console, vai alla pagina Esplora metriche in Cloud Monitoring.

    Vai a Esplora metriche

  2. Fai clic su Seleziona una metrica.

  3. Espandi Destinazione Prometheus > Vllm e seleziona una delle metriche disponibili che terminano con /gauge. Ad esempio, seleziona prometheus/vllm:num_requests_running/gauge per visualizzare il conteggio delle richieste attive durante il test di carico.

Come descritto nella documentazione sulle metriche di produzione vLLM, le metriche vLLM aggiuntive esportate in Cloud Monitoring includono:

  • prometheus/vllm:num_requests_waiting/gauge: il numero di richieste in attesa nella coda di essere elaborate dal motore vLLM.
  • prometheus/vllm:num_requests_running/gauge: il numero di richieste in esecuzione nei batch di modelli.
  • prometheus/vllm:gpu_cache_usage_perc/gauge: la percentuale di memoria della cache KV della GPU utilizzata.
  • prometheus/vllm:num_requests_swapped/gauge: il numero di richieste la cui cache KV è stata scambiata con la memoria della CPU host a causa della pressione della memoria.

Sebbene questo tutorial esegua la scalabilità in base a vllm:num_requests_running, puoi utilizzare una qualsiasi di queste metriche vLLM nella configurazione CREMA per personalizzare le regole di scalabilità automatica per i carichi di lavoro in base alle dimensioni della coda, all'utilizzo della cache KV o allo scambio di richieste.

A differenza delle metriche di concorrenza delle richieste HTTP standard che trattano tutte le richieste allo stesso modo, le metriche interne di vLLM tengono conto dell'impronta di memoria GPU dinamica di diverse lunghezze di prompt. La scalabilità su vllm:num_requests_running ti aiuta a scalare in modo proattivo in base al carico GPU effettivo. In questo modo viene mantenuto un buffer di capacità attivo prima che il server sia costretto a mettere in coda le richieste in vllm:num_requests_waiting, proteggendo gli utenti da picchi di latenza elevati di Time To First Token (TTFT).

Libera spazio

Per evitare addebiti aggiuntivi al tuo Google Cloud account, elimina tutte le risorse di cui hai eseguito il deployment con questo tutorial.

Elimina il progetto

Se hai creato un nuovo progetto per questo tutorial, eliminalo. Se hai utilizzato un progetto esistente e devi conservarlo senza le modifiche aggiunte in questo tutorial, elimina le risorse create per il tutorial.

Il modo più semplice per eliminare la fatturazione è eliminare il progetto che hai creato per il tutorial.

Per eliminare il progetto:

  1. Nella Google Cloud console, vai alla pagina Gestisci risorse.

    Vai a Gestisci risorse

  2. Nell'elenco dei progetti, seleziona il progetto che vuoi eliminare, quindi fai clic su Elimina.
  3. Nella finestra di dialogo, digita l'ID progetto, quindi fai clic su Chiudi per eliminare il progetto.

Elimina le risorse del tutorial

  1. Elimina il servizio Cloud Run di cui hai eseguito il deployment in questo tutorial. I servizi Cloud Run non comportano costi finché non ricevono richieste.

    Per eliminare il servizio Cloud Run, esegui questo comando:

    gcloud run services delete SERVICE-NAME

    Sostituisci SERVICE-NAME con il nome del servizio.

    Puoi eliminare i servizi Cloud Run anche dalla Google Cloud console.

  2. Rimuovi la configurazione della regione predefinita di gcloud che hai aggiunto durante la configurazione del tutorial:

     gcloud config unset run/region
    
  3. Rimuovi la configurazione del progetto:

     gcloud config unset project
    
  4. Elimina la configurazione CREMA assegnata a Parameter Manager:

    gcloud parametermanager parameters delete crema-config \
        --location=global \
        --quiet
    
  5. Elimina l'account di servizio personalizzato creato per CREMA:

    gcloud iam service-accounts delete $CREMA_SA \
        --quiet
    
  6. Elimina il bucket Cloud Storage contenente il modello:

    gcloud storage rm --recursive gs://$BUCKET_NAME
    
  7. Elimina le altre Google Cloud risorse create in questo tutorial:

Passaggi successivi