使用 GPU 指標自動調度 vLLM 模型服務

本教學課程說明如何使用 Cloud Run 外部指標自動調度 (CREMA),根據自訂 GPU 指標,自動調度提供 LLM 服務的 Cloud Run 服務 (使用 vLLM)。

雖然 Cloud Run 預設會根據 CPU 使用率和並行量自動調度資源,但 GPU 密集型推論工作負載通常需要根據佇列指標 (例如執行中的要求數量或 KV 快取使用率) 自動調度資源。CREMA 會整合 Kubernetes 架構的事件驅動自動調度 (KEDA) 與 Cloud Run,根據 Prometheus 指標動態調度資源。vLLM 會公開 Prometheus 指標,並將這些指標傳送至 Cloud Monitoring。

目標

在這個教學課程中,您將執行下列操作:

費用

在本文件中,您將使用下列 Google Cloud計費元件:

如要根據預測用量估算費用,請使用 Pricing Calculator。

初次使用 Google Cloud 的使用者可能符合免費試用期資格。

事前準備

  1. 登入 Google Cloud 帳戶。如果您是 Google Cloud新手,歡迎 建立帳戶,親自評估產品在實際工作環境中的成效。新客戶還能獲得價值 $300 美元的免費抵免額,可用於執行、測試及部署工作負載。
  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. 啟用 Cloud Run、Parameter Manager、Artifact Registry、Cloud Build、Secret Manager 和 Cloud Monitoring API (如尚未啟用)。

    啟用 API 時所需的角色

    如要啟用 API,您必須具備 serviceusage.services.enable 權限。如果您建立了專案,可能已透過「擁有者」角色 (roles/owner) 取得這項權限。否則,您可以透過「服務使用情形管理員」角色 (roles/serviceusage.serviceUsageAdmin) 取得這項權限。瞭解如何授予角色。

    啟用 API

  7. 安裝並初始化 gcloud CLI。
  8. 設定本教學課程中使用的環境變數:
    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
    將 PROJECT_ID 替換為 Google Cloud 專案 ID。
  9. 設定專案設定:
    gcloud config set project $PROJECT_ID
  10. 如果沒有帳戶,請前往 Hugging Face 建立帳戶。接著在 Hugging Face 網站上建立「讀取」權杖。 Hugging Face 只會顯示一次權杖。請將這組金鑰儲存在安全的地方,因為您無法再次查看。
  11. 前往 Hugging Face 的 gemma-2-2b-it 模型頁面,然後接受模型的協議條款。

必要的角色

如要取得完成本教學課程所需的權限,請要求管理員在專案中授予您下列 IAM 角色:

如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和組織的存取權」。

您或許也能透過自訂角色或其他預先定義的角色,取得必要權限。

下載模型權重並上傳至 Cloud Storage

從 Hugging Face 下載模型權重,並轉移至 Cloud Storage bucket,以供提供模型使用:

  1. 安裝 Hugging Face CLI:

    pip install -U "huggingface_hub[cli]"
    
  2. 使用 Hugging Face CLI 在本機下載模型權重:

    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
    

    將 HF_TOKEN 替換為您的 Hugging Face 使用者存取權杖。權杖開頭應為 hf_,後面接著 35 個隨機英數字元 (例如 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)。

  3. 建立 Cloud Storage bucket,並複製下載的權重:

    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/
    

將 vLLM 容器映像檔推送至 Artifact Registry

提取提供模型的容器映像檔,並推送至 Artifact Registry 存放區:

  1. 在 Artifact Registry 建立 Docker 存放區:

    gcloud artifacts repositories create $REPO_NAME \
        --repository-format=docker \
        --location=$REGION \
        --description="vLLM Docker Images"
    
  2. 向登錄檔驗證本機 Docker Daemon:

    gcloud auth configure-docker ${REGION}-docker.pkg.dev
    
  3. 提取 vLLM 映像檔、加上標記,然後推送至 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
    

部署 CREMA 自動調度器服務

部署自動調整規模服務前,請先為 CREMA 設定服務帳戶角色和參數資訊清單。

建立自訂服務帳戶

建立自訂服務帳戶,並僅授予使用佈建資源所需的權限。 這個服務帳戶代表自動調整程式。執行下列指令,建立 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"

將其他權限授予自訂服務帳戶

如要擴充服務,請在自訂服務帳戶中授予下列權限:

  1. 授予 CREMA 服務帳戶從 Parameter Manager 讀取資料的權限:

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/parametermanager.parameterViewer"
    
  2. 授予 CREMA 服務帳戶權限,以便擴充服務:

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/run.developer"
    
  3. 將服務帳戶使用者角色授予 CREMA 服務帳戶:

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/iam.serviceAccountUser"
    
  4. 授予 CREMA 服務帳戶查看指標的權限:

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

建立及註冊 CREMA 設定

在 CREMA 設定資訊清單中定義縮放比例門檻和規則,並在 Parameter Manager 中註冊:

  1. 將下列設定儲存為 my-crema-config.yaml。如果執行中的要求數量 (vllm:num_requests_running) 超過 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. 在 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
    

部署 CREMA 服務

將 CREMA 映像檔部署為 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"

設定 vLLM 服務權限

授予預設 Compute Engine 服務帳戶權限,從 Cloud Storage 匯出指標及讀取模型權重:

  1. 擷取專案編號:

    export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
    
  2. 授予服務帳戶寫入指標的權限:

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
        --role="roles/monitoring.metricWriter"
    
  3. 授予服務帳戶從 Cloud Storage 讀取模型權重的權限:

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

部署 vLLM 服務和 OpenTelemetry 邊車

將主要 vLLM 服務容器部署至 Cloud Run,並從 Cloud Storage 掛接模型權重。由於在 Cloud Run 上部署附有 Sidecar 的多容器服務時,需要宣告式 YAML 服務規格,因此您會設定主要 vLLM 引擎,以及 OpenTelemetry Sidecar 收集器,以便擷取及匯出 vLLM 指標:

  1. 將下列多容器部署規格儲存為 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. 將現有服務設定換成多容器資訊清單:

    gcloud run services replace vllm-service.yaml
    

檢查 CREMA 服務記錄

  1. 前往 Google Cloud 控制台的「Cloud Run」頁面。
  2. 選取crema-service。
  3. 按一下「記錄」分頁標籤,確認指標輪詢週期處於啟用狀態:

    [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 ...
    

執行負載測試

如要測試自動調度資源,請執行負載測試指令碼,將並行要求傳送至 vLLM 服務:

  1. 在目前使用的目錄中,建立名為 load-test.sh 的檔案,並加入下列程式碼:

    #!/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. 將指令碼設為執行檔並執行負載測試:

    chmod +x load-test.sh
    ./load-test.sh
    
  3. 再次檢查 crema-service 記錄和 Cloud Run 指標資訊主頁,確認建議的執行個體數量會因應佇列要求而增加。

在 Cloud Monitoring 中探索 vLLM 指標

執行負載測試後,請探索流量對 Cloud Monitoring 中提供模型指標的影響:

  1. 前往 Google Cloud Cloud Monitoring 中的「Metrics Explorer」頁面。

    前往「Metrics Explorer」。

  2. 按一下「Select a metric」(選取指標)。

  3. 展開「Prometheus Target」 >「Vllm」,然後選取任何以 /gauge 結尾的可用指標。舉例來說,選取 prometheus/vllm:num_requests_running/gauge 即可查看負載測試期間的有效要求計數。

如 vLLM 生產指標說明文件所述,匯出至 Cloud Monitoring 的其他 vLLM 指標包括:

  • prometheus/vllm:num_requests_waiting/gauge:等待 vLLM 引擎處理的要求數。
  • prometheus/vllm:num_requests_running/gauge:在模型批次中執行的要求數量。
  • prometheus/vllm:gpu_cache_usage_perc/gauge:GPU KV 快取記憶體的使用百分比。
  • prometheus/vllm:num_requests_swapped/gauge:由於記憶體壓力,KV 快取已交換至主機 CPU 記憶體的要求數量。

雖然本教學課程是根據 vllm:num_requests_running 進行資源調度,但您可以在 CREMA 設定中使用任何 vLLM 指標,根據佇列大小、KV 快取使用率或要求交換,為工作負載自訂自動調度規則。

與將所有要求視為相同的標準 HTTP 要求並行指標不同,vLLM 的內部指標會考量不同提示長度的動態 GPU 記憶體用量。vllm:num_requests_running 的資源調度功能可根據實際 GPU 負載主動調度資源,這樣一來,伺服器就不會被迫將要求排入佇列 vllm:num_requests_waiting,有助於維持有效的容量緩衝區,避免使用者遇到嚴重的「第一個詞元生成時間」延遲尖峰。

清除所用資源

為避免系統向您的 Google Cloud 帳戶收取額外費用,請刪除您在本教學課程中部署的所有資源。

刪除專案

如果您是為了這個教學課程建立新專案,請刪除該專案。如果您使用現有專案,並想保留專案,但不要本教學課程新增的變更,請刪除為本教學課程建立的資源。

如要避免付費,最簡單的方法就是刪除您為了本教學課程所建立的專案。

刪除專案的方法如下:

  1. 前往 Google Cloud 控制台的「Manage resources」(管理資源) 頁面。

    前往「Manage resources」(管理資源)

  2. 在專案清單中選取要刪除的專案,然後點選「Delete」(刪除)。
  3. 在對話方塊中輸入專案 ID,然後按一下 [Shut down] (關閉) 以刪除專案。

刪除教學課程資源

  1. 刪除您在本教學課程中部署的 Cloud Run 服務。Cloud Run 服務收到要求後才會產生費用。

    如要刪除 Cloud Run 服務,請執行下列指令:

    gcloud run services delete SERVICE-NAME

    將 SERVICE-NAME 改為您的服務名稱。

    您也可以從Google Cloud 控制台刪除 Cloud Run 服務。

  2. 移除您在教學課程設定期間新增的 gcloud 預設區域設定:

     gcloud config unset run/region
    
  3. 移除專案設定:

     gcloud config unset project
    
  4. 刪除指派給 Parameter Manager 的 CREMA 設定:

    gcloud parametermanager parameters delete crema-config \
        --location=global \
        --quiet
    
  5. 刪除為 CREMA 建立的自訂服務帳戶:

    gcloud iam service-accounts delete $CREMA_SA \
        --quiet
    
  6. 刪除內含模型的 Cloud Storage bucket:

    gcloud storage rm --recursive gs://$BUCKET_NAME
    
  7. 刪除在本教學課程中建立的其他 Google Cloud 資源:

後續步驟