OpenTelemetry OpenTelemetry

サンプリングでコストを制御する:SDK と Collector の設定

SDK でサンプリングするか、2 層の Collector で tail サンプリングを使うかを判断します。

15 min learn.level.上級

すべてのトレースを保持すると、すぐに高価になり、そのほとんどは、誰も開くことのない通常のリクエストです。サンプリングは、代表的な、または興味深いサブセットを保持します。OpenTelemetry には、決定を行う場所が 2 つあります。トレースが始まるときの SDK(head サンプリング)と、トレースが完了した後の Collector(tail サンプリング)です。どちらも純粋に設定です。このガイドでは、それぞれと、その選び方を説明します。

SDK での head サンプリング

決定は、ルートのスパンが作成されたときに行われるため、安価で、追加のインフラも必要ありません。リクエストが失敗するか遅くなるかは、まだ起きていないため、知ることができません。

export OTEL_TRACES_SAMPLER=parentbased_traceidratio
export OTEL_TRACES_SAMPLER_ARG=0.1

仕様が定義するサンプラーの名前には、always_on、always_off、traceidratio、parentbased_always_on(デフォルト)、parentbased_always_off、parentbased_traceidratio があります。parentbased_ のバリアントを使ってください。それらは、受信リクエストの親のサンプリングの決定に従うため、トレースは、サービスをまたいで、全体として保持されるか破棄されるかのどちらかになります。各サービスで単純な traceidratio を使うと、独立した決定が行われ、壊れたトレースが生成されます。

宣言的な設定ファイルでは、同じ考え方は次のようになります。

tracer_provider:
  sampler:
    parent_based:
      root:
        trace_id_ratio_based:
          ratio: 0.1

ファイル形式でサポートされているサンプラーの名前については、お使いの SDK のドキュメントを確認してください。

Collector での tail サンプリング

tail サンプリングは、トレースが完了するまで待ち、その後でポリシーを適用します。すべてのエラーとすべての遅いトレースに加えて、残りの小さな割合を保持でき、head サンプリングにはできないことです。コストは、より多くのインフラとメモリです。

processors:
  tail_sampling:
    decision_wait: 10s
    num_traces: 50000
    expected_new_traces_per_sec: 100
    policies:
      - name: keep-errors
        type: status_code
        status_code:
          status_codes: [ERROR]
      - name: keep-slow
        type: latency
        latency:
          threshold_ms: 2000
      - name: sample-the-rest
        type: probabilistic
        probabilistic:
          sampling_percentage: 5

仕組み:

  • decision_wait は、トレースの最初のスパンを見てから、決定するまでに processor が待つ時間です。最も遅いトレースの所要時間より長くする必要があり、そうでないと、不完全なトレースに基づいて決定することになります。
  • num_traces は、待機中にメモリに保持されるトレースの数です。トレースの到着率に decision_wait を掛けたものに、余裕を持たせて、サイズを決めます。
  • policies は、各トレースに対して評価されます。いずれかのポリシーが保持すると言えば、トレースは保持されるため、上の 3 つは、「エラーを保持し、遅いものを保持し、さらにすべての 5% を保持する」という意味になります。
  • 他のポリシーのタイプには、string_attribute(顧客のティアなどの値に一致)、numeric_attribute、always_sample、and(ポリシーの組み合わせ)、composite(ポリシー間でレートを割り当て)があります。

tail_sampling は contrib ディストリビューションにあり、そのオプション名は進化するため、お使いのバージョンの README を確認してください。

落とし穴:1 つのトレースは 1 つの Collector に届く必要がある

tail サンプリングは、トレースのすべてのスパンが同じ Collector インスタンスに到着する場合にのみ機能します。単純なロードバランサーの背後に複数のレプリカがあると、1 つのトレースのスパンが散らばり、断片に基づいて決定が行われます。標準的な解決策は、2 つの層です。

  1. 層 1(ロードバランシングの層) は、loadbalancing exporter を使って、トレース ID で、スパンを一貫した層 2 のインスタンスにルーティングします。
  2. 層 2(サンプリングの層) は、tail_sampling を実行し、保持されたトレースをエクスポートします。

層 1:

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317

exporters:
  loadbalancing:
    routing_key: traceID
    protocol:
      otlp:
        tls:
          insecure: true
    resolver:
      dns:
        hostname: otel-sampler-headless.observability.svc.cluster.local
        port: 4317

service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [loadbalancing]

層 2:

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317

processors:
  memory_limiter:
    check_interval: 1s
    limit_percentage: 80
    spike_limit_percentage: 20
  tail_sampling:
    decision_wait: 10s
    policies:
      - name: keep-errors
        type: status_code
        status_code:
          status_codes: [ERROR]
      - name: sample-the-rest
        type: probabilistic
        probabilistic:
          sampling_percentage: 10
  batch:

exporters:
  otlp/backend:
    endpoint: tempo:4317

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, tail_sampling, batch]
      exporters: [otlp/backend]

DNS が層 2 の Pod を列挙するように、headless Service を使います。Pod がスケールアップまたはダウンすると、ルーティングが変わり、いくつかの処理中のトレースが、不完全なデータで決定される可能性があることに注意してください。層を分けておくことは、障害を分離することにもなります。サンプリングの問題が、取り込みをブロックすることはありません。

head と tail の組み合わせ

一般的で賢明な構成:

  • トラフィックが非常に多いサービスで、ソースでのボリュームを減らすための、SDK での控えめな head サンプラー(たとえば 50%)。
  • エラーと遅いリクエストが生き残ることを保証するための、Collector での tail サンプリング。

注意してください。head で破棄されたものは、tail では回復できません。すべてのエラーを保持する必要がある場合は、それらのサービスに、積極的な head サンプリングを行わないでください。

メトリクスは、先に導出すればサンプリングを生き残る

トレースを破棄すると、そこから計算できる数値、たとえばリクエスト率やレイテンシーのパーセンタイルも失われます。ダッシュボードが正確なままであるように、サンプリングのステップの前に、spanmetrics connector でメトリクスを生成します。

connectors:
  spanmetrics:

service:
  pipelines:
    traces/all:
      receivers: [otlp]
      exporters: [spanmetrics, loadbalancing]
    metrics/derived:
      receivers: [spanmetrics]
      processors: [batch]
      exporters: [otlphttp/prometheus]

ここでは、すべてのスパンが connector に供給され、サンプリングされたセットだけがストレージへと進みます。

選択

目的アプローチ
新しいインフラなしで、シンプルにコストを削減するparentbased_traceidratio での head サンプリング
すべてのエラーと遅いリクエストを保持する2 層の Collector での tail サンプリング
正確なレートとパーセンタイルを保つサンプリングの前の spanmetrics
サービスが少なく、ボリュームが小さいサンプリングなし。コストが問題になったら再検討

確認する

  • 層 2 で、Collector 自身のメトリクス(ポート 8888)を使って、入力と出力のスパン数を比較し、比率がポリシーと一致することを確認します。
  • 既知の失敗したリクエストを検索し、そのトレース全体が存在することを確認します。
  • 層 2 のメモリを監視します。decision_wait の間、トレースを保持しているためです。増加する場合は、num_traces を減らすかレプリカを追加し、memory_limiter を前に置いたままにします。

人気のガイド