Escalonar automaticamente os pools de workers com base no volume da fila do Pub/Sub

Neste tutorial, mostramos como implantar um pool de workers do Cloud Run para processar mensagens do Pub/Sub e escalonar automaticamente as instâncias de consumidor com base na profundidade da fila usando o escalonamento automático de métricas externas do Cloud Run (CREMA).

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, 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 Google Cloud conta do. Se você começou a usar o Google Cloud, 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, Pub/Sub e Cloud Build.

    Funções necessárias para ativar APIs

    Para ativar as APIs, é necessário ter o papel do IAM de administrador de uso do serviço (roles/serviceusage.serviceUsageAdmin), que contém a permissão serviceusage.services.enable. Saiba como conceder papéis.

    Ativar as APIs

  7. Instale e inicialize a CLI gcloud.
  8. Atualize os componentes:
    gcloud components update
  9. Este tutorial usa várias variáveis de ambiente. Para melhorar a depuração, execute o comando a seguir para gerar um erro quando você fizer referências a variáveis de ambiente locais não definidas:
    set -u
  10. Defina as seguintes variáveis de configuração para o CREMA usado neste tutorial:
    export PROJECT_ID=PROJECT_ID
    export REGION=us-central1
    export TOPIC_ID=crema-pubsub-topic
    export SUBSCRIPTION_ID=crema-subscription
    export CREMA_SA_NAME=crema-service-account
    export CONSUMER_SA_NAME=consumer-service-account
    export CONSUMER_WORKER_POOL_NAME=worker-pool-consumer
    export CREMA_SERVICE_NAME=my-crema-service
    Substitua PROJECT_ID pelo ID do seu Google Cloud projeto.
  11. Defina o ID do projeto executando o seguinte comando:
    gcloud config set project $PROJECT_ID
  12. Você incorre em cobranças pelo serviço de escalonamento do Cloud Run com base na frequência com que aciona o escalonamento. Para mais informações, estime os custos com a calculadora de preços.

Funções exigidas

Para conseguir as permissões que você precisa para concluir o tutorial, peça ao administrador para conceder a você os seguintes papéis do IAM no seu 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.

Criar um tópico e uma assinatura do Pub/Sub

Para escalonar automaticamente o worker, crie uma assinatura por pull para o aplicativo de consumidor seguindo estas etapas:

  1. Crie um tópico do Pub/Sub que represente um feed de mensagens:

    gcloud pubsub topics create $TOPIC_ID
    
  2. Crie uma assinatura por pull para consumir mensagens do tópico do Pub/Sub:

    gcloud pubsub subscriptions create $SUBSCRIPTION_ID --topic=$TOPIC_ID
    

Criar contas de serviço personalizadas

Este tutorial exige as duas contas de serviço a seguir com as permissões mínimas necessárias para usar os recursos provisionados:

  • Conta de serviço do consumidor: identidade do pool de workers do consumidor que processa mensagens. Execute o comando a seguir para criar a conta de serviço do consumidor:

    gcloud iam service-accounts create $CONSUMER_SA_NAME \
      --display-name="Pub/Sub consumer service account"
    
  • Conta de serviço do CREMA: identidade do escalonador automático. Execute o comando a seguir para criar a conta de serviço do CREMA:

    gcloud iam service-accounts create $CREMA_SA_NAME \
      --display-name="CREMA service account"
    

Conceder permissões adicionais às contas de serviço personalizadas

Para escalonar o pool de workers, conceda as seguintes permissões nas contas de serviço personalizadas:

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

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

    gcloud projects add-iam-policy-binding $PROJECT_ID \
      --member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
      --role="roles/run.developer"
    
  3. Conceda à 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_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
      --role="roles/iam.serviceAccountUser"
    
  4. Conceda permissão à conta de serviço do CREMA para visualizar métricas:

     gcloud projects add-iam-policy-binding $PROJECT_ID \
       --member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
       --role="roles/monitoring.viewer"
    
  5. Conceda permissão à conta de serviço do CREMA para gravar métricas:

     gcloud projects add-iam-policy-binding $PROJECT_ID \
       --member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
       --role="roles/monitoring.metricWriter"
    
  6. Conceda permissão à conta de serviço do CREMA para visualizar mensagens do Pub/Sub:

    gcloud pubsub subscriptions add-iam-policy-binding $SUBSCRIPTION_ID \
      --member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
      --role="roles/pubsub.viewer"
    
  7. Conceda permissão à conta de serviço do consumidor para extrair mensagens da assinatura:

    gcloud pubsub subscriptions add-iam-policy-binding $SUBSCRIPTION_ID \
      --member="serviceAccount:$CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
      --role="roles/pubsub.subscriber"
    

Implantar um pool de workers do Cloud Run

Para implantar um pool de workers que consome mensagens de assinaturas do Pub/Sub, siga estas etapas:

  1. Crie uma pasta chamada consumer e mude o diretório para ela:

    mkdir consumer
    cd consumer
    
  2. Crie um arquivo chamado worker.py e adicione o seguinte código:

    import os
    import time
    from google.cloud import pubsub_v1
    from concurrent.futures import TimeoutError
    
    # Configuration
    PROJECT_ID = os.environ.get('PROJECT_ID')
    SUBSCRIPTION_ID = os.environ.get('SUBSCRIPTION_ID')
    
    subscription_path = f"projects/{PROJECT_ID}/subscriptions/{SUBSCRIPTION_ID}"
    
    print(f"Worker Pool instance starting. Watching {subscription_path}...")
    
    subscriber = pubsub_v1.SubscriberClient()
    
    def callback(message):
        try:
            data = message.data.decode("utf-8")
            print(f"Processing job: {data}")
            time.sleep(5)  # Simulate work
            print(f"Done {data}")
            message.ack()
        except Exception as e:
            print(f"Error processing message: {e}")
            message.nack()
    
    streaming_pull_future = subscriber.subscribe(subscription_path, callback=callback)
    print(f"Listening for messages on {subscription_path}...")
    
    # Wrap subscriber in a 'with' block to automatically call close() when done.
    with subscriber:
        try:
            # When `timeout` is not set, result() will block indefinitely,
            # unless an exception is encountered first.
            streaming_pull_future.result()
        except TimeoutError:
            streaming_pull_future.cancel()  # Trigger the shutdown.
            streaming_pull_future.result()  # Block until the shutdown is complete.
        except Exception as e:
            print(f"Streaming pull failed: {e}")
    
  3. Crie um Dockerfile e adicione o seguinte código:

    FROM python:3.12-slim
    RUN pip install google-cloud-pubsub
    COPY worker.py .
    CMD ["python", "-u", "worker.py"]
    
  4. Implante o pool de workers do consumidor com 0 instâncias para o CREMA escalonar verticalmente:

    gcloud beta run worker-pools deploy $CONSUMER_WORKER_POOL_NAME \
      --source . \
      --region $REGION \
      --service-account="$CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
      --instances=0 \
      --set-env-vars PROJECT_ID=$PROJECT_ID,SUBSCRIPTION_ID=$SUBSCRIPTION_ID
    

Implantar o serviço de escalonamento automático CREMA

Depois de implantar o pool de workers para consumir mensagens do Pub/Sub, configure o escalonador automático CREMA para provisionar instâncias de worker com base no volume de mensagens.

Configurar o escalonador automático

Este tutorial usa o Gerenciador de parâmetros para armazenar o arquivo de configuração YAML do CREMA.

  1. Crie um parâmetro no Gerenciador de parâmetros para armazenar versões de parâmetros para o CREMA:

    PARAMETER_ID=crema-config
    PARAMETER_REGION=global
    gcloud parametermanager parameters create $PARAMETER_ID --location=$PARAMETER_REGION --parameter-format=YAML
    
  2. Navegue até o diretório raiz do projeto executando o seguinte comando:

    cd
    
  3. No diretório raiz, crie um arquivo YAML, my-crema-config.yaml, para definir a configuração do escalonador automático:

    apiVersion: crema/v1
    kind: CremaConfig
    spec:
      pollingInterval: 30
      triggerAuthentications:
        - metadata:
            name: adc-trigger-auth
          spec:
            podIdentity:
              provider: gcp
      scaledObjects:
        - spec:
            scaleTargetRef:
              name: projects/PROJECT_ID/locations/us-central1/workerpools/worker-pool-consumer
            triggers:
              - type: gcp-pubsub
                metadata:
                  subscriptionName: "crema-subscription"
                  # Target number of undelivered messages per worker instance
                  value: "10"
                  mode: "SubscriptionSize"
                authenticationRef:
                  name: adc-trigger-auth
    

    Substitua PROJECT_ID pelo Google Cloud ID do projeto.

  4. Faça upload do arquivo YAML local como uma nova versão do parâmetro:

    LOCAL_YAML_CONFIG_FILE=my-crema-config.yaml
    PARAMETER_VERSION=1
    
    gcloud parametermanager parameters versions create $PARAMETER_VERSION \
      --location=$PARAMETER_REGION \
      --parameter=$PARAMETER_ID \
      --payload-data-from-file=$LOCAL_YAML_CONFIG_FILE
    
  5. Execute o comando a seguir para verificar se a adição do parâmetro foi bem-sucedida:

    gcloud parametermanager parameters versions list \
    --parameter=$PARAMETER_ID \
    --location=$PARAMETER_REGION
    

    Você verá o caminho do parâmetro, como projects/PROJECT_ID/locations/global/parameters/crema-config/versions/1.

Implantar o serviço para escalonar as cargas de trabalho

Para implantar o serviço para escalonar o pool de workers, execute o comando a seguir com uma imagem de contêiner pré-criada:

CREMA_CONFIG_PARAM_VERSION=projects/$PROJECT_ID/locations/$PARAMETER_REGION/parameters/$PARAMETER_ID/versions/$PARAMETER_VERSION
IMAGE=us-central1-docker.pkg.dev/cloud-run-oss-images/crema-v1/autoscaler:1.0

gcloud beta run deploy $CREMA_SERVICE_NAME \
  --image=${IMAGE} \
  --region=${REGION} \
  --service-account="${CREMA_SA_NAME}" \
  --no-allow-unauthenticated \
  --no-cpu-throttling \
  --base-image=us-central1-docker.pkg.dev/serverless-runtimes/google-24/runtimes/java25 \
  --labels=created-by=crema \
  --set-env-vars="CREMA_CONFIG=${CREMA_CONFIG_PARAM_VERSION},OUTPUT_SCALER_METRICS=True"

Testar o serviço de escalonamento automático

Teste o serviço CREMA criando um script que gera 100 mensagens e as envia para a fila do Pub/Sub:

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

    #!/bin/bash
    
    TOPIC_ID=${TOPIC_ID}
    PROJECT_ID=${PROJECT_ID}
    NUM_MESSAGES=100
    
    echo "Publishing $NUM_MESSAGES messages to topic $TOPIC_ID..."
    
    for i in $(seq 1 $NUM_MESSAGES); do
      gcloud pubsub topics publish $TOPIC_ID --message="job-$i" --project=$PROJECT_ID &
      if (( $i % 10 == 0 )); then
        wait
        echo "Published $i messages..."
      fi
    done
    wait
    echo "Done. All messages published."
    
  2. Execute o teste de carga:

    chmod +x load-pubsub.sh
    ./load-pubsub.sh
    

Esse comando gera e envia 100 mensagens para a assinatura do Pub/Sub.

Monitorar o escalonamento

Depois que o script load-pubsub.sh for concluído, aguarde três a quatro minutos antes de verificar registros para o serviço, my-crema-service. O serviço de escalonamento automático CREMA escalona as instâncias de worker do consumidor de 0.

Você verá os seguintes registros:

Cada mensagem de registro é rotulada com o componente que a emitiu.

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

Como alternativa, execute o comando a seguir para verificar se o serviço CREMA recomenda instâncias com base na profundidade da fila:

gcloud logging read "resource.type=cloud_run_revision AND resource.labels.service_name=$CREMA_SERVICE_NAME AND textPayload:SCALER" \
  --limit=20 \
  --format="value(textPayload)" \
  --freshness=5m

Para visualizar os registros de consumidor que consomem mensagens, execute o seguinte comando:

gcloud beta run worker-pools logs tail $CONSUMER_WORKER_POOL_NAME --region=$REGION

Você verá registros que seguem o formato Done job-100.

Liberar espaço

Para evitar cobranças extras na sua Google Cloud conta, 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 alterações incluídas 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 Google Cloud console, 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 Desligar para excluir o projeto.

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

    pelo nome do serviço;SERVICE-NAME

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

  2. Remova a configuração da região padrão da 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 os recursos do Pub/Sub:

    gcloud pubsub subscriptions delete $SUBSCRIPTION_ID
    gcloud pubsub topics delete $TOPIC_ID
    
  5. Exclua outros Google Cloud recursos criados neste tutorial:

A seguir