> [!abstract] 概要(abstract 日本語訳) > トレーシングはソフトウェアシステムの実行時挙動を解析するための基本的な技術である。メソッド実行の開始・終了時刻とコンテキストメタデータを記録することにより、詳細な性能解析・アーキテクチャ再構成・プログラム理解が可能になる。しかしながら、このような計装は不可避的に実行時オーバーヘッドを導入し、性能計測を歪め、変動を増大させる。このオーバーヘッドをトレーシングフレームワーク・設定をまたいで定量化・比較することは、適切なツールを選択し、信頼性の高い性能評価を保証するために不可欠である。 > 異なるトレーシングフレームワークとその設定のオーバーヘッドは、MooBench マイクロベンチマークによって計測できる。本研究では、MooBench マイクロベンチマークを拡張し、確立された Java トレーシングフレームワークである Elastic APM Agent・inspectIT・Kieker・OpenTelemetry・Pinpoint・Scouter・SkyWalking をサポートした。これらのエージェントを用いて MooBench を実行した結果、(1) 性能オーバーヘッドに大きな差異があること——業界標準実装の OpenTelemetry は比較的遅く、機能的に正しいフレームワークの中では Kieker エージェントが最低のオーバーヘッドを持つ——、(2) Pinpoint と Scouter のエージェントはすべてのレコードを格納せず、その挙動が機能要件を満たさないこと、(3) 一部のフレームワークの回避可能なオーバーヘッドが、過度なメタデータ収集とデータの不必要なコピーによって生じていること、を見出した。 ## 論文情報 - **タイトル**: Benchmarking the Overhead of Distributed Tracing Agents - **著者**: David Georg Reichelt(Lancaster University Leipzig / URZ Leipzig)、Shinhyung Yang(Christian-Albrechts-Universität zu Kiel)、Marcel Hansson(University of Hamburg)、Wilhelm Hasselbring(Christian-Albrechts-Universität zu Kiel) - **媒体**: ICPE '26 — 17th ACM/SPEC International Conference on Performance Engineering - **発表年**: 2026 年 5 月 4〜8 日、フィレンツェ、イタリア - **DOI**: https://doi.org/10.1145/3777884.3797004 - **データセット**: https://doi.org/10.5281/zenodo.17639772 - **ACM バッジ**: Artifacts Available V1.1・Artifacts Evaluated Functional V1.1・Artifacts Evaluated Reusable V1.1 ## 概要 Java 向け主要分散トレーシングエージェント 7 種の計装オーバーヘッドを MooBench マイクロベンチマークで統一的に計測し、根本原因を async-profiler のフレームグラフとコード解析で特定した研究。x86_64(AMD Ryzen 7 5700G)と ARMv8(Raspberry Pi 5)の 2 アーキテクチャで評価。Kieker が最速、Scouter が最遅、OpenTelemetry が業界標準のわりに遅いという結果に至り、その原因をコードレベルで分析した。 ## 問題設定 - **入力**: Java アプリケーション(計装対象)・トレーシングエージェント(Elastic APM / inspectIT / Kieker / OpenTelemetry / Pinpoint / Scouter / SkyWalking)の組み合わせ - **出力**: エージェント別・設定別の計装オーバーヘッド(ns/メソッド呼び出し)と根本原因の分類 - **前提条件**: 非分散ワークロード(MooBench マイクロベンチマーク)。非分散オーバーヘッドは分散シナリオのオーバーヘッドの下限値として機能する - **評価指標**: 実行時間(ns/call)、線形回帰(傾き $a$・切片 $b$)、コールツリー深度スケーラビリティ **MooBench の仕組み**: `monitoredMethod` が `$RECURSION_DEPTH` 深さまで再帰的に自分自身を呼び出し、末端で `$SLEEP_TIME` 待機するベンチマークアプリ。200 万回実行×10 JVM 起動×コールツリー深度 2〜128 で計測。 **トレーシングの 4 ステップ(オーバーヘッドの原因)**: 1. **計装**: バイトコードにプローブコードを織り込む 2. **プローブ実行**: コールツリー情報・開始/終了時刻取得・レコード生成 3. **キューへの挿入**: 非同期処理のためキューへ投入 4. **書き込み**: データシンク(ネットワーク/バイナリファイル)への書き込み ## エージェント選定 GitHub API で「monitoring agent language:Java」「apm agent language:Java」等で検索し、100 スター以上・英語ドキュメント・6 ヶ月以内の最終コミットを条件にフィルタリング。DataDog(研究ライセンス不可)・EaseAgent(メソッドレベルトレーシング非対応)・MyPerf4j(集計メトリクスのみ)は除外。OpenTelemetry は検索結果に出ないが重要性のため手動追加。 | エージェント | GitHub スター数 | 選定理由 | |---|---|---| | Pinpoint | 13.4k | 最多スター。Kafka + HBase + Pinot の λ アーキテクチャ | | Elastic APM | 568 | Elasticsearch スタックの APM 標準 | | inspectIT | 541 | OpenTelemetry 参照実装ベース。YAML 設定 | | Kieker | 108 | MooBench の元々の対象。IRL ベース拡張フレームワーク | | OpenTelemetry | 2k | 業界標準。OpenTracing + OpenCensus を統合 | | Scouter | 2.1k | リアルタイム APM。エージェント + サーバ + クライアント構成 | | SkyWalking | 800 | Apache。クラウドネイティブ・マイクロサービス向け | (Table 1. Benchmarked Tracing Agents より) ## 提案手法 ### MooBench の拡張 既存の MooBench は Kieker・OpenTelemetry・inspectIT に対応していた。本研究では Elastic APM・Pinpoint・Scouter・SkyWalking を追加サポートし、インストール・設定・計装プロセスを自動化。 ``` tools(benchmark) → Kieker-java / OpenTelemetry-java / New Agent frameworks: Kieker-java → 基本定義 OpenTelemetry-java → 基本定義 New Agent → 本研究で追加 ``` 各フレームワークは(1) 計装オフ(計装ステップのオーバーヘッドのみ)、(2) コレクションなし(データ収集オーバーヘッド)、(3) ネットワーク/バイナリファイル書き込み(書き込みオーバーヘッド)の設定を提供。 ### 根本原因分析アプローチ async-profiler(safepoint バイアスを回避する Java サンプリングプロファイラ)を VM 起動 10 秒後にアタッチし、フレームグラフを生成。collapsed ファイルを解析してメソッドを 5 タスクに手動タグ付け: | タスク | 内容 | 計測タイミング | |---|---|---| | **MEMORY** | トレーシングレコードの生成・再利用 | メソッド開始時 | | **TIME** | 開始/終了時刻・時刻関数呼び出し | 開始・終了時 | | **CALL-TREE** | コールツリー構造の格納 | メソッド開始時 | | **METADATA** | クラス名・メソッド名・トレース ID 等の取得 | 開始/終了時 | | **QUEUE** | 監視レコードのキューへの投入 | レコード生成後 | **Figure 7: OpenTelemetry フレームグラフ例** ![[_attachments/3777884.3797004/fig07-flamegraph-opentelemetry.png]] (Figure 7. OpenTelemetry の実行例フレームグラフ。`moobench.application.MonitoredClassSimple.monitoredMethod` が自己再帰し、各レベルで OpenTelemetry のコールが追加されている。一部のコールは赤・橙のネイティブ呼び出し(時刻関数)として現れる。) ## 実験結果 ### ベースライン逐次実行時間(x86_64、代表値) | フレームワーク | 設定 | 実行時間 $\mu$ (ns) | 標準偏差 $\sigma$ (ns) | |---|---|---|---| | Kieker | Binary file | 1,383.33 | 36.63 | | Kieker | No collection | 668.18 | 3.75 | | OpenTelemetry | Zipkin | 3,620.98 | 93.08 | | OpenTelemetry | Prometheus | 3,209.96 | 71.94 | | Elastic APM | Regular Writing | 4,285.96 | 83.86 | | SkyWalking | Instrumentation | 4,601.62 | 101.53 | | inspectIT | Zipkin | 7,029.56 | 124.83 | | Scouter | Instrumentation+Profiling | 14,203.80 | 129.44 | | Pinpoint | Basic | 4,328.52 | 90.10 | (Table 2. Sequential Execution Times(ns)より抜粋。全計測値はデータセット参照) **ランキング(x86_64 デフォルト設定、低い方が優秀)**: Kieker < OpenTelemetry < Elastic APM < Pinpoint < SkyWalking < inspectIT < Scouter ARMv8(Raspberry Pi 5)では絶対値が 2〜4 倍増加するが、相対的ランキングは x86_64 と一致。 ### コールツリー深度スケーラビリティ(線形回帰) すべてのエージェントで $R^2 \geq 0.99$ の線形挙動を確認。 | エージェント | 傾き $a$ (ns/depth) | 切片 $b$ (ns) | $R^2$ | |---|---|---|---| | Kieker | 133.92 | 197.35 | 0.9985 | | OpenTelemetry | 315.28 | 47.67 | 0.9999 | | Elastic APM | 384.66 | 247.92 | 0.9996 | | SkyWalking | 392.13 | 566.39 | 0.9999 | | inspectIT | 656.79 | 308.50 | 0.9999 | | **Pinpoint** | **92.79** | **3348.40** | 0.9918 | | **Scouter** | **133.84** | **13063.42** | 0.9971 | (Table 3. Linear regression analysis より) **Pinpoint と Scouter の異常**: 傾き $a$ は低いが切片 $b$ が桁外れに高い。これはスパンが到達せず意図せず破棄されているためで、傾きが低いのは性能が良いのではなく**レコードを落としている**から。 **Figure 4: スケーラビリティ結果** (ベクター描画のため画像なし。Table 3 参照) ### Pinpoint のスパン損失 SpanGrpcDataSender がスパンを送信しても、GrpcSpanChunkHandler で受信されるのは一部のみ。10 万回のメソッド呼び出しで 30〜40% のレコードのみ表示。ネットワーク障害でも同一サーバでの実行でも再現し、Pinpoint チームとの議論でも原因不明(Issue #12970)。 ### Scouter のレコード損失 デフォルト設定で受信レコード率が 30〜40%。`profile_step_max_keep_in_memory_count` を 2,048 から 1,000,000 に増やすと 99% 受信できるが実行時間が **3,500% 増加**。これでも Scouter が最も遅く、かつ依然としてデータ損失が残る。 ## 根本原因分析 **Figure 8: タスク別時間割合と絶対値** (ベクター描画のため画像なし。以下のテキスト解析による) ### TIME タスク - **時刻関数の実装**: 多くのフレームワークが `System.nanoTime`(CLOCK_MONOTONIC、絶対値不可)を使用。分散トレーシングでは絶対タイムスタンプが必要なため、各フレームワークが独自の `AnchoredClock`(OpenTelemetry)・`EpochTickClock`(Elastic APM)・`SystemNanoTimer`(Kieker)を実装 - **呼び出し回数**: Kieker・Elastic APM は 2 回/メソッド(最小)。OpenTelemetry はバッチエクスポート時にも追加呼び出し。**SkyWalking は 6 回**(インターセプタの前後各 1 回 × 2 + スパンの start/end。さらに `System.currentTimeMillis` を別途使用) ### METADATA タスク - **Kieker**: Byte Buddy の `Advice.Origin` からメソッドシグネチャを直接取得。パース不要・最速 - **OpenTelemetry**: `CodeSpanNameExtractor` が `indexOf` + 文字列連結でクラス名・メソッド名を抽出。`ClassNames` キャッシュの参照にも相当時間。`Attributes`(key-value ペア)を毎回ハッシュマップに変換し、`CodeAttributesExtractor` がさらに別の HashMap を生成。スレッド ID・名前を `AddThreadDetailsSpanProcessor` が設定、ランダム ID を `RandomIdGenerator` が生成——**過度なメタデータ管理が高オーバーヘッドの主因** - **inspectIT**: YAML 設定ファイルを動的に読み込んでクラスを置換・中間クラスを注入するため追加オーバーヘッド - **SkyWalking**: リフレクションでメソッド名と引数を取得し、定数フィールド名のマップに格納 - **Elastic APM**: `trackMetrics` がプロダクションスレッドで定期的にメトリクスを計算 ### CALL-TREE タスク - **OpenTelemetry**: スパン生成のたびに `ArrayBasedContext` を新しいインスタンスにコピー(2 エントリ分の空きを確保)。**スタックコピーの非効率性が高コスト** - **Elastic APM**: `TraceContext`(スレッドローカル `ActiveStack`)でスタックを管理。push/pop は配列デク操作 - **SkyWalking**: `TracingContext` でスタックを管理。インスタンスを再利用(効率的) - **Kieker**: eoi(実行順序インデックス)と ess(実行スタックサイズ)をスレッドローカル変数に格納。スタックコピー不要 ### QUEUE タスク - **Kieker**: `MpscArrayQueue`。書き込みスレッドが 1 スパンずつ連続送信。挿入スレッドがロック解放待ちになる可能性 - **OpenTelemetry**: `MpscAtomicArrayQueue` + `BatchSpanProcessor`。スパンをバッチでまとめて gRPC 経由 Zipkin 等へ送信 - **Elastic APM**: Disruptor ライブラリのリングバッファ。キューオーバーヘッドを最小化 - **SkyWalking**: `ArrayBlockingQueue`。スタックが空になった(トレースが完了した)後にセグメント全体を送信 ### フレームグラフ(付録) **Figure 11: Kieker フレームグラフ** ![[_attachments/3777884.3797004/fig11-flamegraph-kieker.png]] (Figure 11. Kieker のフレームグラフ。時刻関数呼び出しの割合が比較的高く、キュー書き込み待ち([`BlockingQueueDecorator.offer`] → [`pthread_cond_signal`])が実行時間の大部分を占める。) **Figure 14: SkyWalking フレームグラフ** ![[_attachments/3777884.3797004/fig14-flamegraph-skywalking.png]] (Figure 14. SkyWalking のフレームグラフ。`org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/v2/InstMethodsInterV2.intercept` が多重に積み重なり、インターセプタ機構のスタック深さが特徴的。) ## 強み・弱点と課題 **強み**: - 7 種の主要 Java エージェントを統一ベンチマーク(MooBench)で比較した初の包括的研究 - 根本原因分析をコードレベル(async-profiler + ソースコード手動解析)まで実施 - 2 アーキテクチャ(x86_64・ARMv8)で評価し、相対的ランキングの再現性を確認 - MooBench の拡張・設定の自動化・データセット公開(Zenodo)による再現性担保 **弱点・限界**: - **外部妥当性**: MooBench は非分散・単一ユーザ・CPU バウンドのマイクロベンチマーク。マイクロサービスアーキテクチャ・非同期リクエスト処理・ディスク集中処理等では結果が大きく変わりうる - **内部妥当性**: JVM 非決定性・ガベージコレクションによる残留ノイズ。隠れバックグラウンドスレッドやバッチ機構がタイミングに影響 - **構成妥当性**: メソッド境界の追加レイテンシを計測するが、フレームワークの意図する用途(RPC トレーシング等)と完全に一致するとは限らない - **ハードウェア限定**: デスクトップ・サーバハードウェアのみ。GraalVM・Eclipse OpenJ9・RISC-V 等では異なる結果になる可能性 - DataDog・OneAgent(Dynatrace)は評価外 ## 改善提言(Discussion §6 より) 1. **TIME**: SkyWalking の時刻関数呼び出しを削減(自己オペレーション時間計測をオプション化)。`AnchoredClock` 相当の実装を採用 2. **METADATA**: OpenTelemetry・Elastic APM・SkyWalking・inspectIT はメタデータの HashMap コピーを回避すべき。計装ツールから直接メタデータを取得(リフレクション回避) 3. **CALL-TREE**: OpenTelemetry はスタックコピーを除去すべき。全ツールが eoi/ess 方式(Kieker)でコールツリーを表現可能かを検討 4. **MEMORY**: Elastic APM 以外の全フレームワークがリングバッファによる効率的なメモリ管理を検討すべき 5. **QUEUE**: SkyWalking のようにスパン個別送信でなくトレース完了後のセグメント送信方式が有効かを全ツールで評価 ## 関連研究との位置づけ - **MooBench の先行利用**: Waller+ 2015(CI への組み込み)・Reichelt+ 2021(OpenTelemetry/inspectIT/Kieker の比較)の拡張 - **個別エージェントの自己ベンチマーク**: Pinpoint・OpenTelemetry が公開しているが、ベンダー特有でクロス比較不可 - **マイクロサービスブラックボックス計測**: eBPF を使った手法([[@2022__IEEE CLOUD__Localizing and Explaining Faults in Microservices Using Distributed Tracing]])は別系統。最大 4.49% のオーバーヘッドを報告するが、per-call 値ではなく全体値のため本研究との直接比較不可 - **Linux カーネルトレーシング**: LTTng が 2006 年のハードウェアで平均 288.5 サイクル(96.15 ns)——現代の Java エージェントより低いオーバーヘッド ## 関連 - 著者: [[David Georg Reichelt]] / [[Shinhyung Yang]] / [[Marcel Hansson]] / [[Wilhelm Hasselbring]] - ツール/システム: [[MooBench]] / [[Kieker]] / [[OpenTelemetry]] / [[Elastic APM]] / [[inspectIT]] / [[Pinpoint]] / [[SkyWalking]] / [[Scouter]] / [[async-profiler]] - 概念: [[分散トレーシング]] / [[トレーシングオーバーヘッド]] / [[継続的プロファイリング]] / [[ゼロコード計装]] / [[動的計装]] / [[本番接地型ベンチマーク]] - 関連ソース: [[@2026__arXiv__ARGUS - Production-Scale Tracing and Performance Diagnosis for over 10,000-GPU Clusters]] / [[@2026__OTelBlog__OTel-Arrow-Phase-2]] - 関連 MOC: [[AIOps - Fault Localization - MOC]] ## 出典 - PDF: `.raw/papers/3777884.3797004.pdf`(15 ページ、ICPE '26 ACM) - データセット: https://doi.org/10.5281/zenodo.17639772 - Table 2(Sequential Execution Times)、Table 3(Linear regression)、Figure 7(OpenTelemetry flame graph)、Figure 8(Duration Root Causes)、付録 Figure 9〜14(各エージェントフレームグラフ)