監控 GKE 上的強化學習工作負載

本文說明如何針對在 Google Kubernetes Engine (GKE) 上執行的 Python 強化學習 (RL) 應用程式,發出、收集及查看重要指標和追蹤記錄。

本文說明如何執行下列操作:

  • 為 RL 應用程式設定檢測,發出指標和追蹤記錄。使用的檢測功能適用於符合 OpenTelemetry 格式的指標和追蹤記錄。
  • 在應用程式於 GKE 上執行時收集指標和追蹤記錄。資料是使用 GKE 適用的代管 OpenTelemetry (預先發布版) 收集。
  • 在 Cloud Monitoring 中查看收集到的指標,並在 Cloud Trace 中查看追蹤記錄。
  • 根據 OpenTelemetry 語意慣例和黃金信號,找出並瞭解重要的 RL 指標。黃金訊號是服務的四項重要指標,可提供服務健康狀態的高階概覽:延遲時間流量錯誤飽和度

事前準備

  1. 請確認您有想使用指標和追蹤資料監控的 Python 型 RL 應用程式。

  2. 確認您有 Google Cloud 已啟用計費功能的專案。

  3. 您需要執行 GKE 1.34.1-gke.2178000 以上版本的 GKE 叢集,才能使用 GKE 代管 OpenTelemetry (預先發布版)。

  4. 啟用下列 Google Cloud API:

    • container.googleapis.com (GKE)
    • monitoring.googleapis.com (監控)
    • cloudtrace.googleapis.com (追蹤)
    • telemetry.googleapis.com (OpenTelemetry Telemetry API)

    您可以使用 gcloud 啟用這些 API:

    gcloud services enable \
        container.googleapis.com \
        monitoring.googleapis.com \
        cloudtrace.googleapis.com \
        telemetry.googleapis.com
    
  5. 安裝 OpenTelemetry SDK:在 Python RL 應用程式的環境中,安裝 OpenTelemetry SDK 和 OTLP Exporter:

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

    您可能也需要 RL 應用程式所用架構的檢測程式庫,例如 opentelemetry-instrumentation-flask

費用

將遙測資料傳送至 Google Cloud時,系統會根據擷取量向您收費。指標費用會依據 Google Cloud Managed Service for Prometheus 定價計費,記錄費用會依據 Cloud Logging 定價計費,追蹤記錄費用則會依據 Cloud Trace 定價計費。

如要瞭解擷取追蹤記錄、記錄和 Google Cloud Managed Service for Prometheus 指標的相關費用,請參閱「Google Cloud Observability 定價」一文。

使用 OpenTelemetry 檢測應用程式

檢測 Python RL 應用程式程式碼,以便發出 OpenTelemetry 指標。如要檢測應用程式,請執行下列操作:

  1. 將下列程式碼加入應用程式,初始化 OpenTelemetry:

    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. 為每個指標建立工具,並記錄應用程式要發出的值。以屬性形式附加相關語意慣例。

    請參閱語意慣例和黃金信號清單,判斷要為應用程式設定哪些指標。

    以下是特定指標的工具範例:

    # 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()
    

您已初始化 OpenTelemetry,並為特定指標建立檢測項目,現在應用程式會在執行時發出指定的遙測資料。

在 GKE 中啟用指標和追蹤資料收集功能

如要收集應用程式在執行時發出的遙測資料,可以使用 GKE 適用的 Managed OpenTelemetry (搶先版)。這項功能會收集指標和追蹤記錄等遙測資料,並將資料傳送至 Google Cloud Observability。

如要為 GKE 啟用及設定代管 OpenTelemetry,請完成下列步驟:

  1. 在應用程式執行的叢集上,為 GKE 啟用 Managed OpenTelemetry。如要啟用這項功能,請按照「在叢集中啟用 GKE 的代管 OpenTelemetry」一文中的步驟操作。

  2. 使用環境變數為應用程式 Deployment 加上註解,引導 OpenTelemetry SDK 將遙測資料傳送至代管收集器的 OTLP 端點。如果是以 Python 為基礎的 RL 應用程式,您無法使用 Managed OpenTelemetry for GKE 的自動設定功能。

    請改為在部署資訊清單中,將下列 env 區段新增至容器規格:

    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
    

應用程式完成檢測,且已啟用及設定代管收集器後,應用程式在 GKE 叢集上執行時,指標和追蹤記錄就會傳送至 Google Cloud Observability。

您可以在 Monitoring 和 Trace 中查看這項遙測資料。

在 Monitoring 中查看指標

在啟用 Managed OpenTelemetry 的情況下,RL 應用程式在 GKE 上執行後,指標就會傳送至 Monitoring。指標通常位於 prometheus.googleapis.com/ 網域下方。

如要在 Monitoring 中查看自訂 RL 指標,請按照下列步驟操作:

  1. 如要在資訊主頁中查看 RL 指標,請執行下列任一操作:

  2. 在資訊主頁的「指標」欄位中,搜尋開頭為 prometheus.googleapis.com/ 的指標。可用的指標與您在應用程式中插碼的指標相對應。這類指標的例子包括:

    • prometheus.googleapis.com/rl_loop_duration_histogram/
    • prometheus.googleapis.com/rl_sample_samples_total/
    • prometheus.googleapis.com/rl_environment_reward_mean_total/
  3. 篩選和分組:您可以在 Metrics Explorer 中使用篩選器,運用您新增為屬性的語意慣例。舉例來說,下列程式碼會指定特定執行和演算法的迴圈時間長度:

    • 篩選條件:metric.label."rl_run_id" == "run-42"
    • 篩選條件:metric.label."rl_algorithm" == "PPO"
    • 分組依據:metric.label."rl_environment_name" 比較不同環境的成效。

在 Trace 中查看追蹤記錄

分散式追蹤記錄會提供作業時間軸,協助您偵錯 RL 系統中的執行流程。

  1. 在 Google Cloud 控制台中開啟 Google Cloud 控制台的「Trace Explorer」

    前往「Trace Explorer」頁面

  2. 您可以查詢及篩選追蹤記錄。由於您將 "service.name": "rl-training-service" 設為資源屬性,因此可以依 resource.labels.service_name="rl-training-service" 篩選追蹤記錄。

    追蹤記錄中的個別範圍代表 RL 工作負載的不同部分。視您在應用程式中設定追蹤的方式而定,這些範圍可能包含對外部服務的呼叫,或 RL 迴圈的不同階段。

RL 語意慣例和黃金信號

本節列出 OpenTelemetry 指標,有助於找出 RL 應用程式在 GKE 上執行時發生的問題。

請使用本節中的資訊執行下列操作:

  • 決定要為應用程式收集哪些指標和追蹤記錄。
  • 決定如何查看及使用從應用程式收集的指標和追蹤記錄資料。

如要使用 OpenTelemetry 有效監控 RL 工作負載,建議您著重於「黃金信號」。黃金信號是服務的四項重要指標,可提供服務健康狀態的概略總覽:延遲時間流量錯誤飽和度。為 RL 應用程式設定這些指標,即可快速瞭解及偵錯效能問題。

以下各節列出語意慣例,以及依黃金信號分類的指標名稱,這些信號代表 RL 環境中的指標。

RL 語意慣例

以下是指標的屬性。這些屬性提供脈絡資訊,方便您在監控功能中進行篩選和分析。

  • RL_SYSTEM = "rl.system":RL 系統或框架的名稱 (例如「MyCustomRL」)。
  • RL_SYSTEM_VERSION = "rl.system.version":RL 系統版本。
  • RL_RUN_ID =「rl.run.id」:特定訓練執行的專屬 ID。
  • RL_ALGORITHM =「rl.algorithm」:使用的 RL 演算法 (例如「PPO」、「DQN」)。
  • RL_ENVIRONMENT_NAME =「rl.environment.name」:RL 環境的名稱 (例如「CartPole-v1」)。
  • RL_MODEL_NAME = "rl.model.name":政策/價值模型的名稱或 ID。
  • RL_LOOP =「rl.loop」:主要訓練迴圈的 ID。
  • RL_LOOP_ITERATION = "rl.loop.iteration":RL 迴圈的目前疊代次數。
  • RL_SAMPLE = "rl.sample":取樣階段的背景資訊。
  • RL_SAMPLE_EPISODES =「rl.sample.episodes」:取樣的集數。
  • RL_SAMPLE_STEPS =「rl.sample.steps」:取樣的步驟數。
  • RL_SAMPLE_BATCH_SIZE = "rl.sample.batch_size":取樣時使用的批量大小。
  • RL_REWARD =「rl.reward」:用於計算獎勵的脈絡。
  • RL_REWARD_BATCH_SIZE = "rl.reward.batch_size":用於計算獎勵的批量大小。
  • RL_REWARD_SANDBOX = "rl.reward.sandbox":獎勵計算沙箱的 ID。
  • RL_TRAIN = "rl.train":訓練階段的背景資訊。
  • RL_TRAIN_STEPS = "rl.train.steps":訓練步數。
  • RL_TRAIN_BATCH_SIZE = "rl.train.batch_size":訓練期間使用的批量。
  • RL_TRAIN_TOKENS =「rl.train.tokens」:訓練期間處理的權杖數量。
  • RL_SYNC = "rl.sync":同步作業的環境。
  • RL_SYNC_BYTES =「rl.sync.bytes」:同步期間傳輸的位元組。
  • RL_SYNC_SOURCE = "rl.sync.source":同步處理的來源。
  • RL_SYNC_DESTINATION = "rl.sync.destination": 同步處理目的地。

黃金信號和 RL 指標

以下各節列出與四個黃金訊號相關的 RL 指標:延遲流量錯誤飽和度

如要進一步瞭解黃金信號,請參閱《Google Site Reliability Engineering》(SRE) 一書第 6 章的「四大黃金信號」。

延遲時間

完成主要作業需要多久時間?延遲時間過長可能表示完成重要作業時發生延遲。下列指標有助於找出 RL 應用程式在 GKE 上執行時發生的延遲問題。

  • rl.loop.duration (直方圖):迴圈時間過長會減慢整個訓練過程。監控這項指標有助於找出 RL 週期任何部分的成效衰退情形。
  • rl.sample.duration (直方圖):取樣速度緩慢會直接影響產生新訓練資料的速度。
  • rl.reward.duration (直方圖):獎勵計算可能很複雜;追蹤延遲時間有助於最佳化這個重要步驟。
  • rl.train.duration (直方圖):訓練時間對於疊代速度至關重要。如果這裡出現尖峰,可能表示訓練演算法或硬體有問題。
  • rl.sync.duration (直方圖):有效率的同步處理對於分散式 RL 至關重要。同步時間過長可能會導致資料過時,並減緩學習速度。
  • rl.step.duration (直方圖):個別環境步驟的細部延遲時間。

流量和輸送量

完成多少工作?如果總處理量偏低,可能表示資源使用效率不彰。當 RL 應用程式在 GKE 上執行時,下列指標可協助您找出流量或總處理量的任何問題。

  • rl.sample.samples (計數器):代表收集到的體驗資料量。如果出現下降情形,表示取樣程序有問題。
  • rl.sample.episodes (計數器):追蹤完整劇集播放次數。
  • rl.train.steps (計數器):以最佳化步驟為單位,測量訓練進度。
  • rl.train.tokens (計數器):追蹤處理的詞元總數。這項指標適用於大型模型 RL。
  • rl.tokens.rate / rl.tokens.rate_per_gpu (量表/速率):直接測量訓練速度和效率,特別是基於詞元的模型。
  • rl.samples.rate / rl.samples.rate_per_gpu (測量/速率):測量系統收集新樣本的速度。

錯誤

是否有任何效能或執行錯誤?在 RL 中,「錯誤」可能會以非預期的行為或效能不佳的形式呈現。下列指標可協助您找出 RL 應用程式在 GKE 上執行時發生的任何錯誤。

  • rl.environment.reward.mean (量表):雖然不是傳統錯誤,但平均回饋大幅下降是重要信號,表示代理程式或環境互動發生問題。這項指標可直接反映學習進度和代理程式效能。
  • rl.environment.episode.length.mean (量表):類似回饋,單集長度若出現非預期變化,可能表示有問題。
  • rl.train.loss (量表):訓練損失突然增加或出現不穩定的行為,表示模型學習成效不佳。訓練穩定性和成功率的基本指標。

飽和度

系統是否過載?高飽和度可能會導致效能降低。下列指標可協助您找出 RL 應用程式在 GKE 上執行時發生的飽和度問題。

  • rl.train.mfu (量表):模型 Flop 使用率 (MFU)。顯示訓練期間運算資源 (例如 GPU 或 TPU) 的使用效率。如果 MFU 偏低,表示使用率不足或出現瓶頸。

後續步驟