🔬

telemetrygenでOpenTelemetry Collectorの性能を分析する

に公開

こんにちは。Splunk Observability Cloudの導入支援を行っている kntr_nkgm です。

OpenTelemetry Advent Calendar 2025の記事です。

https://qiita.com/advent-calendar/2025/otel

はじめに

OpenTelemetry Collectorを運用していると、パフォーマンス調査やキャパシティプランニングが必要になるケースがあります。本番環境に導入する前に「どれぐらいの負荷に耐えられるのか」を把握したい、「今の設定でボトルネックはないか」を確認したいといった場面です。

今回は、OpenTelemetryプロジェクト公式の負荷生成ツール telemetrygen を使って、OTel Collectorに負荷をかけ、その挙動を確認してみます。

telemetrygen とは

telemetrygen は、OpenTelemetryプロジェクト公式の負荷生成ツールです。Traces、Metrics、Logsの3つのシグナルタイプのテストデータを生成できます。

https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/cmd/telemetrygen

主な用途としては以下が挙げられます:

  • OTel Collectorのパフォーマンステスト: 本番環境に近い負荷をかけて性能を検証
  • 開発・検証環境でのテストデータ生成: ダッシュボードやアラートの動作確認
  • デモ環境の構築: 継続的にデータを流し続けることでリアルな環境を再現

OTLPプロトコル(gRPCまたはHTTP)を使ってデータを送信するため、OpenTelemetry Collectorはもちろん、OTLPをサポートする任意のバックエンドに対してデータを送信して処理を確認することもできます。

インストール

telemetrygenのインストールは非常にシンプルです。Goがインストール済みの環境であれば、以下のコマンドでインストールできます。

go install github.com/open-telemetry/opentelemetry-collector-contrib/cmd/telemetrygen@latest

インストール後、ヘルプを確認してみましょう。

telemetrygen --help

オプションは以下のように表示されます。

Telemetrygen simulates a client generating traces, metrics, and logs

Usage:
  telemetrygen [command]

Examples:
telemetrygen traces
telemetrygen metrics
telemetrygen logs

Available Commands:
  help        Help about any command
  logs        Simulates a client generating metrics. (Stability level: development)
  metrics     Simulates a client generating metrics. (Stability level: development)
  traces      Simulates a client generating traces. (Stability level: alpha)

Flags:
  -h, --help   help for telemetrygen

Use "telemetrygen [command] --help" for more information about a command.

Dockerを使う場合は、コンテナイメージも提供されています。

docker pull ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:latest

基本的な使い方

telemetrygenは、サブコマンドで生成するシグナルタイプを指定します。

主なオプション

よく使うオプションをまとめておきます。

オプション 説明
--otlp-endpoint OTel Collectorのエンドポイント(デフォルト: localhost:4317)
--otlp-insecure TLSなしで接続(開発環境用)
--otlp-http HTTPエクスポーターを使用(デフォルトはgRPC)
--rate 1秒あたりの生成数
--duration 実行時間(例: 60s, 5m, 1h)。infで無限に実行
--traces / --metrics / --logs 生成する総数(durationと併用しない)
--workers 並列ワーカー数(デフォルト: 1)

Tracesの生成

最もシンプルな例として、10個のトレースを生成してみます。

telemetrygen traces --otlp-endpoint localhost:4317 --otlp-insecure --traces 10

ターミナル上には以下のようなログが出力されます。

2025-12-25T07:45:27.878Z        INFO    traces/traces.go:53     starting gRPC exporter
2025-12-25T07:45:27.878Z        INFO    grpclog/component.go:69 [core] original dial target is: "localhost:4317"        {"grpc_log": true}
2025-12-25T07:45:27.878Z        INFO    channelz/trace.go:200   [core] [Channel #1] Channel created for target "localhost:4317" {"grpc_log": true}
2025-12-25T07:45:27.878Z        INFO    channelz/trace.go:200   [core] [Channel #1] parsed dial target is: resolver.Target{URL:url.URL{Scheme:"dns", Opaque:"", User:(*url.Userinfo)(nil), Host:"", Path:"/localhost:4317", RawPath:"", OmitHost:false, ForceQuery:false, RawQuery:"", Fragment:"", RawFragment:""}}     {"grpc_log": true}
2025-12-25T07:45:27.878Z        INFO    channelz/trace.go:200   [core] [Channel #1] Channel authority set to "localhost:4317"   {"grpc_log": true}
2025-12-25T07:45:27.878Z        INFO    traces/traces.go:119    generation of traces is limited {"per-second": 1}
2025-12-25T07:45:29.879Z        INFO    channelz/trace.go:200   [core] [Channel #1] Channel exiting idle mode   {"grpc_log": true}
2025-12-25T07:45:29.885Z        INFO    channelz/trace.go:200   [core] [Channel #1] Resolver state updated: {
  "Addresses": [
    {
      "Addr": "127.0.0.1:4317",
      "ServerName": "",
      "Attributes": null,
      "BalancerAttributes": null,
      "Metadata": null
    }
  ],
  "Endpoints": [
    {
      "Addresses": [
        {
          "Addr": "127.0.0.1:4317",
          "ServerName": "",
          "Attributes": null,
          "BalancerAttributes": null,
          "Metadata": null
        }
      ],
      "Attributes": null
    }
  ],
  "ServiceConfig": null,
  "Attributes": null
} (resolver returned new addresses)     {"grpc_log": true}
2025-12-25T07:45:29.885Z        INFO    channelz/trace.go:200   [core] [Channel #1] Channel Connectivity change to CONNECTING   {"grpc_log": true}
2025-12-25T07:45:29.885Z        INFO    channelz/trace.go:200   [core] [Channel #1 SubChannel #2] Subchannel created    {"grpc_log": true}
2025-12-25T07:45:29.885Z        INFO    channelz/trace.go:200   [core] [Channel #1 SubChannel #2] Subchannel Connectivity change to CONNECTING  {"grpc_log": true}
2025-12-25T07:45:29.885Z        INFO    channelz/trace.go:200   [core] [Channel #1 SubChannel #2] Subchannel picks a new address "127.0.0.1:4317" to connect    {"grpc_log": true}
2025-12-25T07:45:29.886Z        INFO    channelz/trace.go:200   [core] [Channel #1 SubChannel #2] Subchannel Connectivity change to READY       {"grpc_log": true}
2025-12-25T07:45:29.886Z        INFO    grpclog/prefix_logger.go:42     [pick-first-leaf-lb] [pick-first-leaf-lb 0xc000426000] SubConn 0xc0000ee500 reported connectivity state READY and the health listener is disabled. Transitioning SubConn to READY.       {"grpc_log": true}
2025-12-25T07:45:29.886Z        INFO    channelz/trace.go:200   [core] [Channel #1] Channel Connectivity change to READY        {"grpc_log": true}
2025-12-25T07:45:46.879Z        INFO    traces/worker.go:180    traces generated        {"worker": 0, "traces": 10}
2025-12-25T07:45:46.879Z        INFO    traces/traces.go:75     stop the batch span processor
2025-12-25T07:45:46.880Z        INFO    channelz/trace.go:200   [core] [Channel #1] Channel Connectivity change to SHUTDOWN     {"grpc_log": true}
2025-12-25T07:45:46.880Z        INFO    channelz/trace.go:200   [core] [Channel #1] Closing the name resolver   {"grpc_log": true}
2025-12-25T07:45:46.880Z        INFO    channelz/trace.go:200   [core] [Channel #1] ccBalancerWrapper: closing  {"grpc_log": true}
2025-12-25T07:45:46.880Z        INFO    channelz/trace.go:200   [core] [Channel #1 SubChannel #2] Subchannel Connectivity change to SHUTDOWN    {"grpc_log": true}
2025-12-25T07:45:46.880Z        INFO    channelz/trace.go:200   [core] [Channel #1 SubChannel #2] Subchannel deleted    {"grpc_log": true}
2025-12-25T07:45:46.880Z        INFO    grpclog/prefix_logger.go:42     [transport] [client-transport 0xc0001f0908] Closing: rpc error: code = Canceled desc = grpc: the client connection is closing   {"grpc_log": true}
2025-12-25T07:45:46.880Z        INFO    grpclog/prefix_logger.go:42     [transport] [client-transport 0xc0001f0908] loopyWriter exiting with error: rpc error: code = Canceled desc = grpc: the client connection is closing     {"grpc_log": true}
2025-12-25T07:45:46.880Z        INFO    channelz/trace.go:200   [core] [Channel #1] Channel deleted     {"grpc_log": true}
2025-12-25T07:45:46.880Z        INFO    traces/traces.go:65     stopping the exporter

継続的に負荷をかける場合は、--rate--durationオプションを使います。以下の例では、1秒間に10トレースを60秒間生成し続けます。

telemetrygen traces --otlp-endpoint localhost:4317 --otlp-insecure --rate 10 --duration 60s

メトリクスやログも同様です。

メトリクス
telemetrygen metrics --otlp-endpoint localhost:4317 --otlp-insecure --rate 100 --duration 60s
ログ
telemetrygen logs --otlp-endpoint localhost:4317 --otlp-insecure --rate 50 --duration 60s

実際に負荷をかけてみる

それでは実際に、telemetrygenを使ってOTel Collectorに負荷をかけ、その挙動を確認してみましょう。

今回は検証用のLinuxサーバにSplunk Distro of OpenTelemetry Collectorを導入します。Splunk Distro of OTel Collectorは、デフォルトでOTel Collectorの内部メトリクスをSplunk Observability Cloudに送信するようになっています。

telemetrygenで負荷をかける

それでは、telemetrygenを使ってOTel Collectorに負荷をかけてみます。今回は1秒間に1000トレースを生成してみましょう。

telemetrygen traces --otlp-endpoint localhost:4317 --otlp-insecure --rate 1000 --duration 300s

Splunk Observability Cloudには、OTel Collectorのパフォーマンスを監視するためのデフォルトダッシュボードが用意されています。
「Dashboards」から「OpenTelemetry Collector」を選択すると、各Collectorのメトリクスを確認できます。

OTel Collectorダッシュボード

負荷をかけてみると、OTel CollectorのOTLPレシーバーが約1000 spans/secでトレースを受け入れ、Exporterがotlphttpとsignalfxのエンドポイントにそれぞれ送信していることが確認できます。

受信と送信のメトリクス

ドロップされたスパンも確認しましょう。Sending queue dropped spansとDropped spans per processorのグラフを見ると、どちらも0で推移しており、データロスが発生していないことがわかります。

ドロップメトリクス

Secondary monitoringセクションでは、Sending queue lengthを確認できます。キューの長さは0で安定しており、Collectorが余裕を持って処理できていることを示しています。

キューの状態

エラー関連のメトリクスも確認します。Exporter - Send failed rate(送信失敗率)とReceivers - Refusal rate(受信拒否率)のどちらも0で推移しており、正常に動作していることが確認できます。

エラーメトリクス

複数のワーカーを使って並列に送信することで、より高い負荷をかけることもできます。

例えばトレースを秒間10000件、10のWorkerから送信してみます。

telemetrygen traces --otlp-endpoint localhost:4317 --otlp-insecure --rate 10000 --duration 300s --workers 10

すると、Sending Queue Lengthのチャートが1を記録するタイミングが出てきましたね。キューにデータが積まれたものの、その後すぐに送信されているように見えます。

キューの状態

※右のチャートは別のテレメトリに関するデータの残りなのでここでは無視してください!

まとめ

今回は、OpenTelemetry公式の負荷生成ツールtelemetrygenを使って、OTel Collectorのパフォーマンスを分析する方法を紹介しました。

telemetrygenは非常にシンプルなツールですが、OTel Collectorの性能検証やキャパシティプランニングには十分な機能を備えています。負荷を変えながら内部メトリクスを観察することで、ボトルネックの特定やチューニングのポイントを見つけることができます。

それでは、良い年末を!

Discussion