Escalonamento automático da veiculação de modelos vLLM com métricas de GPU

Este tutorial descreve como fazer o escalonamento automático dos serviços do Cloud Run que veiculam LLMs com vLLM com base em métricas personalizadas de GPU usando o escalonamento automático de métricas externas do Cloud Run (CREMA).

Embora o Cloud Run faça o escalonamento automático usando a utilização da CPU e a simultaneidade por padrão, as cargas de trabalho de inferência com uso intenso de GPU geralmente exigem o escalonamento automático com base em métricas de fila, como o número de solicitações em execução ou a utilização do cache KV. O CREMA integra o escalonamento automático orientado por eventos (KEDA, na sigla em inglês) baseado no Kubernetes com o Cloud Run para ativar o escalonamento dinâmico impulsionado por métricas do Prometheus. O vLLM expõe as métricas do Prometheus e as envia para o Cloud Monitoring.

Objetivos

Com este tutorial, você vai:

Custos

Neste documento, você vai usar os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços.

Novos usuários do Google Cloud podem estar qualificados para um teste sem custo financeiro.

Antes de começar

  1. Faça login na sua conta do Google Cloud . Se você começou a usar o Google Cloudagora, crie uma conta para avaliar o desempenho dos nossos produtos em situações reais. Clientes novos também recebem US$ 300 em créditos para executar, testar e implantar cargas de trabalho.
  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. Ative as APIs Cloud Run, Gerenciador de parâmetros, Artifact Registry, Cloud Build, Secret Manager e Cloud Monitoring, se alguma delas ainda não estiver ativada.

    Funções necessárias para ativar APIs

    Para ativar APIs, você precisa da permissão serviceusage.services.enable. Se você criou o projeto, provavelmente já tem essa permissão pelo papel de Proprietário (roles/owner). Caso contrário, é possível receber essa permissão pelo papel de Administrador do Service Usage (roles/serviceusage.serviceUsageAdmin). Saiba como conceder papéis.

    Ativar as APIs

  7. Instale e inicialize a CLI gcloud.
  8. Defina as variáveis de ambiente usadas neste 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
    Substitua PROJECT_ID pelo ID do projeto Google Cloud .
  9. Defina a configuração do projeto:
    gcloud config set project $PROJECT_ID
  10. Se você ainda não tiver uma, crie uma conta no Hugging Face. Em seguida, crie um token de leitura no site Hugging Face. O Hugging Face mostra o token apenas uma vez. Salve em um local seguro, porque não será possível acessar de novo.
  11. Navegue até a página do modelo gemma-2-2b-it no Hugging Face e aceite os termos do contrato.

Funções exigidas

Para receber as permissões necessárias para concluir o tutorial, peça para o administrador conceder a você os seguintes papéis do IAM no projeto:

Para mais informações sobre a concessão de papéis, consulte Gerenciar o acesso a projetos, pastas e organizações.

Também é possível conseguir as permissões necessárias por meio de papéis personalizados ou de outros papéis predefinidos.

Fazer o download e upload dos pesos do modelo para o Cloud Storage

Faça o download dos pesos do modelo do Hugging Face e transfira para um bucket do Cloud Storage para disponibilizá-los para a disponibilização do modelo:

  1. Instale a CLI do Hugging Face:

    pip install -U "huggingface_hub[cli]"
    
  2. Faça o download dos pesos do modelo localmente usando a CLI do 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
    

    Substitua HF_TOKEN pelo seu token de acesso de usuário do Hugging Face. O token precisa começar com hf_ seguido de 35 caracteres alfanuméricos aleatórios (por exemplo, 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).

  3. Crie um bucket do Cloud Storage e copie os pesos baixados:

    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/
    

Envie a imagem do contêiner vLLM para o Artifact Registry

Extraia as imagens do contêiner de disponibilização do modelo e envie-as para um repositório no Artifact Registry:

  1. Criar um repositório do Docker no Artifact Registry:

    gcloud artifacts repositories create $REPO_NAME \
        --repository-format=docker \
        --location=$REGION \
        --description="vLLM Docker Images"
    
  2. Autentique o daemon do Docker local com o registro:

    gcloud auth configure-docker ${REGION}-docker.pkg.dev
    
  3. Extraia a imagem do vLLM, marque-a e envie-a por push para o 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
    

Implante o serviço de escalonador automático do CREMA

Configure as funções da conta de serviço e os manifestos de parâmetros para o CREMA antes de implantar o serviço de escalonamento automático.

Criar uma conta de serviço personalizada

Crie uma conta de serviço personalizada com as permissões mínimas necessárias para usar os recursos provisionados. Essa conta de serviço atua como a identidade do escalonador automático. Execute o seguinte comando para criar a conta de serviço do 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"

Conceder outras permissões à sua conta de serviço personalizada

Para escalonar o serviço, conceda as seguintes permissões à conta de serviço personalizada:

  1. Conceda à sua conta de serviço do CREMA permissão para ler do Gerenciador de parâmetros:

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/parametermanager.parameterViewer"
    
  2. Conceda à conta de serviço do CREMA permissão para escalonar o serviço:

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/run.developer"
    
  3. Conceda à sua conta de serviço do CREMA o função do usuário da conta de serviço:

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$CREMA_SA" \
        --role="roles/iam.serviceAccountUser"
    
  4. Conceda à sua conta de serviço do CREMA permissão para visualizar métricas:

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

Criar e registrar a configuração do CREMA

Defina limites e regras de escalonamento em um manifesto de configuração do CREMA e registre-o no Gerenciador de parâmetros:

  1. Salve a configuração a seguir como my-crema-config.yaml. Essa configuração aciona o escalonamento quando o número de solicitações em execução (vllm:num_requests_running) excede 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. Registre o arquivo de configuração no Gerenciador de parâmetros:

    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
    

Implantar o serviço CREMA

Implante a imagem do CREMA como um serviço interno em segundo plano no 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"

Configurar permissões do serviço vLLM

Conceda à conta de serviço padrão do Compute Engine permissões para exportar métricas e ler pesos de modelos do Cloud Storage:

  1. Recupere o número do projeto:

    export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
    
  2. Conceda permissão à sua conta de serviço para gravar métricas:

    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
        --role="roles/monitoring.metricWriter"
    
  3. Conceda à sua conta de serviço permissão para ler pesos de modelo do Cloud Storage:

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

Implantar o serviço vLLM com o arquivo secundário do OpenTelemetry

Implante o contêiner principal de exibição do vLLM no Cloud Run com pesos de modelo montados no Cloud Storage. Como a implantação de serviços de vários contêineres com arquivos secundários no Cloud Run exige uma especificação de serviço YAML declarativa, configure o mecanismo vLLM principal com um coletor de arquivo secundário do OpenTelemetry para extrair e exportar métricas do vLLM:

  1. Salve a seguinte especificação de implantação de vários contêineres como 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. Substitua a configuração de serviço atual pelo manifesto de vários contêineres:

    gcloud run services replace vllm-service.yaml
    

Verificar os registros do serviço CREMA

  1. No console Google Cloud , navegue até a página do Cloud Run.
  2. Escolha suas crema-service.
  3. Clique na guia Registros e verifique se os ciclos de polling de métricas estão ativos:

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

Executar um teste de carga

Para testar o escalonamento automático, execute um script de teste de carga para enviar solicitações simultâneas ao serviço vLLM:

  1. No diretório de trabalho, crie um arquivo chamado load-test.sh e adicione o seguinte código:

    #!/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. Torne o script executável e faça o teste de carga:

    chmod +x load-test.sh
    ./load-test.sh
    
  3. Verifique novamente os registros do crema-service e o painel de métricas do Cloud Run para verificar se a contagem de instâncias recomendada aumenta em resposta às solicitações enfileiradas.

Conhecer as métricas de vLLM no Cloud Monitoring

Depois de executar o teste de carga, explore como o tráfego afeta as métricas de disponibilização do modelo no Cloud Monitoring:

  1. No console do Google Cloud , acesse a página Metrics Explorer no Cloud Monitoring.

    Acessar o Metrics Explorer

  2. Clique em Selecionar uma métrica.

  3. Expanda Destino do Prometheus > Vllm e selecione qualquer uma das métricas disponíveis que terminam em /gauge. Por exemplo, selecione prometheus/vllm:num_requests_running/gauge para conferir a contagem de solicitações ativas durante o teste de carga.

Conforme descrito na documentação de métricas de produção do vLLM, outras métricas do vLLM exportadas para o Cloud Monitoring incluem:

  • prometheus/vllm:num_requests_waiting/gauge: o número de solicitações aguardando na fila para serem processadas pelo mecanismo vLLM.
  • prometheus/vllm:num_requests_running/gauge: o número de solicitações em execução em lotes de modelos.
  • prometheus/vllm:gpu_cache_usage_perc/gauge: a porcentagem de memória do cache KV da GPU utilizada.
  • prometheus/vllm:num_requests_swapped/gauge: o número de solicitações em que o cache de KV foi trocado para a memória da CPU do host devido à pressão da memória.

Embora este tutorial faça o escalonamento com base em vllm:num_requests_running, é possível usar qualquer uma dessas métricas do vLLM na configuração do CREMA para personalizar as regras de escalonamento automático das cargas de trabalho com base no tamanho da fila, na utilização do cache KV ou na troca de solicitações.

Ao contrário das métricas de simultaneidade de solicitações HTTP padrão, que tratam todas as solicitações da mesma forma, as métricas internas do vLLM consideram a pegada dinâmica de memória da GPU de diferentes tamanhos de comandos. O escalonamento no vllm:num_requests_running ajuda você a escalonar de forma proativa com base na carga real da GPU. Isso mantém um buffer de capacidade ativo antes que o servidor seja forçado a enfileirar solicitações em vllm:num_requests_waiting, protegendo os usuários de picos graves de latência do tempo até o primeiro token (TTFT, na sigla em inglês).

Limpar

Para evitar cobranças extras na sua conta do Google Cloud , exclua todos os recursos implantados com este tutorial.

Excluir o projeto

Se você criou um novo projeto para este tutorial, exclua-o. Se você usou um projeto atual e precisa mantê-lo sem as mudanças adicionadas neste tutorial, exclua os recursos criados para o tutorial.

O jeito mais fácil de evitar cobranças é excluindo o projeto que você criou para o tutorial.

Para excluir o projeto:

  1. No console Google Cloud , acesse a página Gerenciar recursos.

    Acessar "Gerenciar recursos"

  2. Na lista de projetos, selecione o projeto que você quer excluir e clique em Excluir .
  3. Na caixa de diálogo, digite o ID do projeto e clique em Encerrar para excluí-lo.

Excluir recursos do tutorial

  1. Exclua o serviço do Cloud Run que você implantou neste tutorial. Os serviços do Cloud Run não geram custos até receberem solicitações.

    Para excluir o serviço do Cloud Run, execute o seguinte comando:

    gcloud run services delete SERVICE-NAME

    SERVICE-NAME pelo nome do serviço;

    Também é possível excluir os serviços do Cloud Run no Google Cloud console do.

  2. Remova a configuração de região padrão gcloud que você adicionou durante a configuração do tutorial:

     gcloud config unset run/region
    
  3. Remova a configuração do projeto:

     gcloud config unset project
    
  4. Exclua a configuração do CREMA atribuída ao Gerenciador de parâmetros:

    gcloud parametermanager parameters delete crema-config \
        --location=global \
        --quiet
    
  5. Exclua a conta de serviço personalizada criada para o CREMA:

    gcloud iam service-accounts delete $CREMA_SA \
        --quiet
    
  6. Exclua o bucket do Cloud Storage que contém o modelo:

    gcloud storage rm --recursive gs://$BUCKET_NAME
    
  7. Exclua outros recursos do Google Cloud criados neste tutorial:

A seguir