Monitorar cargas de trabalho de aprendizado por reforço no GKE

Este documento mostra como emitir, coletar e visualizar métricas e traces importantes para aplicativos de aprendizado por reforço (RL, na sigla em inglês) baseados em Python em execução no Google Kubernetes Engine (GKE).

Esta página mostra como fazer o seguinte:

  • Instrumentar o aplicativo de RL para emitir métricas e traces. A instrumentação usada é para métricas e traces que seguem o formato OpenTelemetry.
  • Coletar métricas e traces quando o aplicativo é executado no GKE. Os dados são coletados usando o OpenTelemetry gerenciado para GKE (pré-lançamento).
  • Visualizar as métricas coletadas no Cloud Monitoring e os traces no Cloud Trace.
  • Identificar e entender métricas de RL críticas com base nas convenções semânticas do OpenTelemetry e nos indicadores de ouro. Os indicadores de ouro são as quatro métricas principais de um serviço que fornecem uma visão geral de alto nível da integridade dele: latência, tráfego, erros e saturação.

Antes de começar

  1. Verifique se você tem um aplicativo de RL baseado em Python que quer monitorar usando métricas e dados de trace.

  2. Você precisa ter um Google Cloud projeto do com o faturamento ativado.

  3. É necessário um cluster do GKE que execute a versão 1.34.1-gke.2178000 ou mais recente do GKE, que são as versões em que o OpenTelemetry gerenciado para GKE (pré-lançamento) está disponível.

  4. Ative as seguintes Google Cloud APIs:

    • container.googleapis.com (GKE)
    • monitoring.googleapis.com (Monitoring)
    • cloudtrace.googleapis.com (Trace)
    • telemetry.googleapis.com (API Telemetry do OpenTelemetry)

    É possível ativar essas APIs usando gcloud:

    gcloud services enable \
        container.googleapis.com \
        monitoring.googleapis.com \
        cloudtrace.googleapis.com \
        telemetry.googleapis.com
    
  5. Instalar o SDK do OpenTelemetry:no ambiente do aplicativo de RL do Python, instale o SDK do OpenTelemetry e o exportador OTLP:

    pip install opentelemetry-sdk \
                opentelemetry-exporter-otlp-proto-grpc \
                opentelemetry-api
    

    Talvez você também precise de bibliotecas de instrumentação para qualquer framework usado pelo app de RL, por exemplo, opentelemetry-instrumentation-flask.

Custos

Ao enviar dados de telemetria para Google Cloud, você recebe cobranças pelo volume de ingestão. As métricas são cobradas usando os preços do Google Cloud Managed Service para Prometheus, os registros são cobrados usando os preços do Cloud Logging e os traces são cobrados usando os preços do Cloud Trace.

Para informações sobre os custos associados à ingestão de traces, registros e métricas do Google Cloud Managed Service para Prometheus, consulte os preços do Google Cloud Observability.

Instrumentar o aplicativo com o OpenTelemetry

Instrumente o código do aplicativo de RL do Python para que ele possa emitir métricas do OpenTelemetry. Para instrumentar o aplicativo, faça o seguinte:

  1. Inicialize o OpenTelemetry adicionando o seguinte código ao aplicativo:

    import os
    import time
    from opentelemetry import metrics, trace
    from opentelemetry.sdk.metrics import MeterProvider
    from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
    from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.sdk.trace.export import BatchSpanProcessor
    from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
    from opentelemetry.sdk.resources import Resource
    from opentelemetry.metrics import Counter, Histogram, UpDownCounter
    
    resource = Resource.create({
        "service.name": "rl-training-service",
        "service.namespace": "opentelemetry-demo",
    })
    
    # Initialize Metrics
    reader = PeriodicExportingMetricReader(
        OTLPMetricExporter(
            endpoint=os.environ.get("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT", "localhost:4317"),
            insecure=True
        )
    )
    meter_provider = MeterProvider(metric_readers=[reader], resource=resource)
    metrics.set_meter_provider(meter_provider)
    meter = metrics.get_meter("rl-training-meter")
    
    # Initialize Tracing
    trace_provider = TracerProvider(resource=resource)
    trace_processor = BatchSpanProcessor(
        OTLPSpanExporter(
            endpoint=os.environ.get("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", "localhost:4317"),
            insecure=True
        )
    )
    trace_provider.add_span_processor(trace_processor)
    trace.set_tracer_provider(trace_provider)
    tracer = trace.get_tracer("rl-training-tracer")
    
  2. Crie instrumentos para cada métrica e registre os valores que você quer que o aplicativo emita. Anexe convenções semânticas relevantes como atributos.

    Use a lista de convenções semânticas e indicadores de ouro para ajudar a determinar quais métricas instrumentar para seu aplicativo.

    Confira a seguir um exemplo de instrumentos para métricas específicas:

    # Latency Histograms
    rl_loop_duration = meter.create_histogram(
        name="rl.loop.duration", description="Duration of a single RL loop iteration.", unit="ms"
    )
    rl_sample_duration = meter.create_histogram(
        name="rl.sample.duration", description="Duration of the sampling phase.", unit="ms"
    )
    rl_train_duration = meter.create_histogram(
        name="rl.train.duration", description="Duration of the training phase.", unit="ms"
    )
    # ... create other duration histograms (reward, train, sync, step)
    
    # Throughput Counters
    rl_sample_samples = meter.create_counter(
        name="rl.sample.samples", description="Number of samples generated.", unit="{samples}"
    )
    rl_train_steps = meter.create_counter(
        name="rl.train.steps", description="Number of training steps completed.", unit="{steps}"
    )
    # ... create other counter metrics (rl.sample.episodes, rl.train.tokens)
    
    # Performance/Saturation Gauges (using UpDownCounter)
    rl_reward_mean = meter.create_up_down_counter(
        name="rl.environment.reward.mean", description="Mean reward observed.", unit="1"
    )
    rl_train_loss = meter.create_up_down_counter(
        name="rl.train.loss", description="Current training loss.", unit="1"
    )
    rl_train_mfu = meter.create_up_down_counter(
        name="rl.train.mfu", description="Model Flop Utilization.", unit="1"
    )
    _rl_reward_mean_val, _rl_train_loss_val = 0.0, 0.0
    
    def get_common_attributes(rl_system, rl_run_id, rl_algorithm, rl_env_name, rl_model_name):
        return {
            "rl.system": rl_system,
            "rl.run.id": rl_run_id,
            "rl.algorithm": rl_algorithm,
            "rl.environment.name": rl_env_name,
            "rl.model.name": rl_model_name,
        }
    
    # Example Usage within your RL code:
    common_attrs = get_common_attributes("MyPPO", "run-42", "PPO", "Acrobot-v1", "PolicyModelV1")
    
    # Inside the main RL loop:
    with tracer.start_as_current_span("rl_loop_iteration", attributes={**common_attrs, "rl.loop.iteration": 5}) as span:
        loop_start_time = time.perf_counter()
    # --- Sampling Phase ---
    sample_start = time.perf_counter()
    # ... perform sampling ...
    sampled_count = 1024
    rl_sample_samples.add(sampled_count, attributes={**common_attrs, "rl.sample.batch_size": 128})
    rl_sample_duration.record((time.perf_counter() - sample_start) * 1000, attributes=common_attrs)
    
    # --- Training Phase ---
    train_start = time.perf_counter()
    # ... perform training step ...
    rl_train_steps.add(1, attributes={**common_attrs, "rl.loop.iteration": 5})
    current_loss = 0.125
    rl_train_loss.add(current_loss - _rl_train_loss_val, attributes=common_attrs) # Record current loss
    _rl_train_loss_val = current_loss
    rl_train_duration.record((time.perf_counter() - train_start) * 1000, attributes=common_attrs)
    
    # --- Record Mean Reward ---
    current_mean_reward = -5.5
    rl_reward_mean.add(current_mean_reward - _rl_reward_mean_val, attributes=common_attrs)
    _rl_reward_mean_val = current_mean_reward
    
    loop_duration = (time.perf_counter() - loop_start_time) * 1000
    rl_loop_duration.record(loop_duration, attributes={**common_attrs, "rl.loop.iteration": 5})
    
    # Ensure metrics are pushed before application exit in short-lived scripts
    # For long-running services, PeriodicExportingMetricReader handles this.
    # meter_provider.shutdown()
    

Agora que você inicializou o OpenTelemetry e criou instrumentos para métricas específicas, o aplicativo emite os dados de telemetria especificados quando é executado.

Ativar a coleta de métricas e dados de trace no GKE

Para coletar os dados de telemetria que o aplicativo emite durante a execução, você pode usar o OpenTelemetry gerenciado para GKE (pré-lançamento). Esse recurso coleta dados de telemetria, como métricas e traces, e os envia para o Google Cloud Observability.

Para ativar e configurar o OpenTelemetry gerenciado para GKE, faça o seguinte:

  1. Ative o OpenTelemetry gerenciado para GKE no cluster em que o aplicativo é executado. Para fazer isso, siga as etapas em Ativar o OpenTelemetry gerenciado para GKE em um cluster.

  2. Anote a implantação do aplicativo com variáveis de ambiente para direcionar o SDK do OpenTelemetry a enviar dados de telemetria para o endpoint OTLP do coletor gerenciado. Para um aplicativo de RL baseado em Python, não é possível usar o recurso de configuração automática do OpenTelemetry gerenciado para GKE.

    Em vez disso, adicione a seguinte seção env à especificação do contêiner no manifesto de implantação:

    env:
      - name: OTEL_COLLECTOR_NAME
        value: 'opentelemetry-collector'
      - name: OTEL_COLLECTOR_NAMESPACE
        value: 'gke-managed-otel'
      - name: OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
        value: $(OTEL_COLLECTOR_NAME).$(OTEL_COLLECTOR_NAMESPACE).svc.cluster.local:4317
      - name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
        value: $(OTEL_COLLECTOR_NAME).$(OTEL_COLLECTOR_NAMESPACE).svc.cluster.local:4317
      - name: OTEL_SERVICE_NAME
        value: 'rl-training-service'
      - name: OTEL_RESOURCE_ATTRIBUTES
        value: service.namespace=opentelemetry-demo
    

Agora que o aplicativo está instrumentado e o coletor gerenciado está ativado e configurado, quando o aplicativo é executado no cluster do GKE, as métricas e os traces são enviados para o Google Cloud Observability.

É possível visualizar esses dados de telemetria no Monitoring e no Trace.

Visualizar métricas no Monitoring

Depois que o aplicativo de RL estiver em execução no GKE com o OpenTelemetry gerenciado ativado, as métricas serão enviadas para o Monitoring. As métricas geralmente estão disponíveis no domínio prometheus.googleapis.com/.

Para visualizar as métricas de RL personalizadas no Monitoring, faça o seguinte:

  1. Para visualizar as métricas de RL em um painel, faça uma destas ações:

  2. No campo Métrica do painel, pesquise métricas que começam com prometheus.googleapis.com/. As métricas disponíveis correspondem às que você instrumentou no aplicativo. Exemplos dessas métricas podem incluir:

    • prometheus.googleapis.com/rl_loop_duration_histogram/
    • prometheus.googleapis.com/rl_sample_samples_total/
    • prometheus.googleapis.com/rl_environment_reward_mean_total/
  3. Filtragem e agrupamento:é possível usar os filtros no Metrics Explorer para aproveitar as convenções semânticas adicionadas como atributos. Por exemplo, o seguinte especifica a duração do loop para uma execução e um algoritmo específicos:

    • Filtro: metric.label."rl_run_id" == "run-42"
    • Filtro: metric.label."rl_algorithm" == "PPO"
    • Agrupar por: metric.label."rl_environment_name" para comparar o desempenho em ambientes.

Visualizar traces no Trace

Os traces distribuídos fornecem uma linha do tempo de operações e ajudam a depurar o fluxo de execução no sistema de RL.

  1. No Google Cloud console, abra o Trace Explorer no Google Cloud console:

    Acessar a página "Trace Explorer"

  2. É possível consultar e filtrar traces. Como você definiu "service.name": "rl-training-service" como um atributo de recurso, é possível filtrar traces por resource.labels.service_name="rl-training-service".

    Os períodos individuais em um trace representam diferentes partes da carga de trabalho de RL. Esses períodos podem incluir chamadas para serviços externos ou diferentes fases do loop de RL, dependendo de como você instrumentou o rastreamento no aplicativo.

Convenções semânticas e indicadores de ouro de RL

Esta seção lista as métricas do OpenTelemetry que podem ajudar a identificar problemas que ocorrem quando o aplicativo de RL é executado no GKE.

Use as informações desta seção para fazer o seguinte:

  • Decidir quais métricas e traces coletar para seu aplicativo.
  • Decidir como visualizar e usar as métricas e os dados de trace coletados do aplicativo.

Para monitorar cargas de trabalho de RL de maneira eficaz usando o OpenTelemetry, é útil se concentrar nos "indicadores de ouro". Os indicadores de ouro são as quatro métricas principais de um serviço que fornecem uma visão geral de alto nível da integridade dele: latência, tráfego, erros e saturação. Ao instrumentar o aplicativo de RL com essas métricas, é possível entender e depurar rapidamente problemas de desempenho.

As seções a seguir têm as convenções semânticas e os nomes de métricas categorizados pelos indicadores de ouro que representam em um contexto de RL.

Convenções semânticas de RL

A seguir estão os atributos das métricas. Esses atributos fornecem contexto para filtragem e análise no Monitoring.

  • RL_SYSTEM = "rl.system": o nome do sistema ou framework de RL (por exemplo, "MyCustomRL").
  • RL_SYSTEM_VERSION = "rl.system.version": versão do sistema de RL.
  • RL_RUN_ID = "rl.run.id": identificador exclusivo de uma execução de treinamento específica.
  • RL_ALGORITHM = "rl.algorithm": o algoritmo de RL que está sendo usado (por exemplo, "PPO", "DQN").
  • RL_ENVIRONMENT_NAME = "rl.environment.name": o nome do ambiente de RL (por exemplo, "CartPole-v1").
  • RL_MODEL_NAME = "rl.model.name": o nome ou identificador do modelo de política/valor.
  • RL_LOOP = "rl.loop": identificador do loop de treinamento principal.
  • RL_LOOP_ITERATION = "rl.loop.iteration": número de iteração atual do loop de RL.
  • RL_SAMPLE = "rl.sample": contexto para a fase de amostragem.
  • RL_SAMPLE_EPISODES = "rl.sample.episodes": número de episódios amostrados.
  • RL_SAMPLE_STEPS = "rl.sample.steps": número de etapas amostradas.
  • RL_SAMPLE_BATCH_SIZE = "rl.sample.batch_size": tamanho do lote usado durante a amostragem.
  • RL_REWARD = "rl.reward": contexto para o cálculo de recompensa.
  • RL_REWARD_BATCH_SIZE = "rl.reward.batch_size": tamanho do lote para o cálculo de recompensa.
  • RL_REWARD_SANDBOX = "rl.reward.sandbox": identificador da sandbox de cálculo de recompensa.
  • RL_TRAIN = "rl.train": contexto para a fase de treinamento.
  • RL_TRAIN_STEPS = "rl.train.steps": número de etapas de treinamento.
  • RL_TRAIN_BATCH_SIZE = "rl.train.batch_size": tamanho do lote usado durante o treinamento.
  • RL_TRAIN_TOKENS = "rl.train.tokens": número de tokens processados durante o treinamento.
  • RL_SYNC = "rl.sync": contexto para operações de sincronização.
  • RL_SYNC_BYTES = "rl.sync.bytes": bytes transferidos durante a sincronização.
  • RL_SYNC_SOURCE = "rl.sync.source": origem da sincronização.
  • RL_SYNC_DESTINATION = "rl.sync.destination": destino da sincronização.

Indicadores de ouro e métricas de RL

As seções a seguir listam as métricas de RL relacionadas aos quatro indicadores de ouro: latência, tráfego, erros e saturação.

Para mais detalhes sobre os indicadores de ouro, consulte Os quatro indicadores de ouro no capítulo 6 do livro Engenharia de confiabilidade do site do Google (SRE, na sigla em inglês).

Latência

Quanto tempo leva para concluir as principais operações? A latência alta pode indicar atrasos ao concluir as principais operações. As métricas a seguir podem ajudar a identificar problemas de latência que ocorrem quando o aplicativo de RL é executado no GKE.

  • rl.loop.duration (histograma): a duração alta do loop desacelera todo o processo de treinamento. O monitoramento ajuda a identificar regressões de desempenho em qualquer parte do ciclo de RL.
  • rl.sample.duration (histograma): a amostragem lenta afeta diretamente a rapidez com que novos dados são gerados para treinamento.
  • rl.reward.duration (histograma): o cálculo de recompensa pode ser complexo. O rastreamento da latência ajuda a otimizar essa etapa crítica.
  • rl.train.duration (histograma): o tempo de treinamento é essencial para a velocidade de iteração. Os picos podem indicar problemas no algoritmo de treinamento ou no hardware.
  • rl.sync.duration (histograma): a sincronização eficiente é essencial na RL distribuída. Tempos de sincronização longos podem causar dados desatualizados e desacelerar o aprendizado.
  • rl.step.duration (histograma): latência granular de etapas ambientais individuais.

Tráfego e capacidade de processamento

Quanto trabalho está sendo feito? A baixa capacidade de processamento pode significar uso ineficiente de recursos. As métricas a seguir podem ajudar a identificar problemas de tráfego ou capacidade de processamento que ocorrem quando o aplicativo de RL é executado no GKE.

  • rl.sample.samples (contador): representa o volume de dados de experiência coletados. Uma queda indica problemas no processo de amostragem.
  • rl.sample.episodes (contador): rastreia o número de episódios completos executados.
  • rl.train.steps (contador): mede o progresso do treinamento em termos de etapas de otimização.
  • rl.train.tokens (contador): rastreia o total de tokens processados. Essa métrica é relevante para RL de modelos grandes.
  • rl.tokens.rate / rl.tokens.rate_per_gpu (medidor/taxa): medidas diretas de velocidade e eficiência de treinamento, especialmente em modelos baseados em tokens.
  • rl.samples.rate / rl.samples.rate_per_gpu (medidor/taxa): mede a rapidez com que o sistema está coletando novas amostras.

Erros

Há erros de desempenho ou execução? Na RL, os "erros" podem se manifestar como comportamento inesperado ou desempenho ruim. As métricas a seguir podem ajudar a identificar erros que ocorrem quando o aplicativo de RL é executado no GKE.

  • rl.environment.reward.mean (medidor): embora não seja um erro tradicional, uma queda drástica na recompensa média é um sinal crítico de que algo está errado com o agente ou a interação do ambiente. Essa métrica reflete diretamente o progresso do aprendizado e o desempenho do agente.
  • rl.environment.episode.length.mean (medidor): semelhante à recompensa, mudanças inesperadas na duração do episódio podem sinalizar problemas.
  • rl.train.loss (medidor): um aumento repentino ou um comportamento errático na perda de treinamento indica que o modelo não está aprendendo de maneira eficaz. Indicador fundamental de estabilidade e sucesso do treinamento.

Saturação

O sistema está sobrecarregado? A saturação alta pode levar à degradação do desempenho. A métrica a seguir pode ajudar a identificar problemas de saturação que ocorrem quando o aplicativo de RL é executado no GKE.

  • rl.train.mfu (medidor): utilização de Flop do modelo (MFU, na sigla em inglês). Indica a eficácia com que os recursos de computação (como GPUs ou TPUs) estão sendo usados durante o treinamento. O MFU baixo sugere subutilização ou gargalos.

A seguir