# Hindsight: Tracing Edge-Cases in Distributed Systems NSDI 2023。Lei Zhang(Emory University / Princeton University)、Zhiqiang Xie・Vaastav Anand・[[Jonathan Mace]]([[Max Planck Institute for Software Systems]])、Ymir Vigfusson(Emory University)。 ## 問題設定 大規模分散システムのエッジケース(テイルレイテンシ・エラー・キュー詰まり等)のトラブルシューティングでは、エンドツーエンドの一貫的(coherent)なトレースが不可欠である。しかし、現行の分散トレーシングフレームワークはオーバーヘッドとエッジケース捕捉率のトレードオフに直面する。(Source: [[@2023__NSDI__Hindsight - Tracing Edge-Cases in Distributed Systems|本論文]] §1–2) - **ヘッドサンプリング**: リクエスト開始時に確率的にサンプルを決定。オーバーヘッドは低い(Jaeger 既定 0.1%)が、エッジケースを見逃す(0.1% の確率でしか捕捉できない)。 - **テイルサンプリング**: バックエンドで全トレースを構築した後にフィルタリング。エッジケースを特定できるが、全トレースデータの取り込みが必要で、アプリケーションスループットが最大 42% 低下し、ネットワーク帯域は最大 78 MB/s を消費する。バックプレッシャーでスパンが非一貫的にドロップされ、負荷が上がるほどトレースの一貫性が急速に劣化する。 ## 提案: 遡及的サンプリング(retroactive sampling) [[Hindsight]] は「症状検出後に過去のトレースデータを遅延的に収集する」遡及的サンプリングという抽象化を導入する。ドライブレコーダーが衝撃検出時に過去映像を保全するのと同じ原理である。(Source: 本論文 §3) 核となる洞察: 1. **トレースデータ生成は低コスト**: ローカルメモリへの書き込みはナノ秒級。高コストなのはネットワーク転送とバックエンド取り込みである。 2. **症状はローカルに観測可能**: エラーコード・テイルレイテンシ・例外はリクエスト処理中または直後にプログラムで検知できる。トレースデータ構築後に検知する必要はない。 3. **トリガーはローカルだがトレースデータは分散**: ブレッドクラム(breadcrumb)をリクエスト伝播経路に沿って預託し、トリガー発火時にコーディネータが再帰的にたどり、関連する全エージェントに収集を指示する。 4. **トレースデータはいずれ期限切れになる**: イベントホライズン(event horizon)と呼ぶ暗黙的な時間窓(既定 1 GB のバッファプールで約 1 分)内にトリガーが発火すれば捕捉できる。 ## 設計 ### データプレーンとコントロールプレーンの分離(§4.2) - **データプレーン**: アプリケーションスレッドが共有メモリのバッファプール(既定 32 kB バッファ)にトレースデータを直接書き込む。同期はバッファ取得/返却時のみで、tracepoint 呼び出しはスレッドローカルバッファへの memcpy。 - **コントロールプレーン**: Hindsight エージェント(各ノード 1 プロセス)がメタデータのみを処理。traceId ごとのバッファ ID リスト・ブレッドクラムをインデックスし、トリガーを受信して収集を調整。エージェントはバッファ内容に一切触れない。 ### トレース一貫性(§4.1) 一貫性は設計全体の最上位要件である。 - **エビクション**: traceId 単位でアトミックに行う。一部スパンのみ破棄は行わない。 - **ブレッドクラムトラバーサル**: コーディネータがリクエストのグラフをたどり、関連エージェントのみに接触。93 サービスで数ミリ秒〜86 ms。 - **過負荷時の一貫性ハッシュ**: traceId の一貫性ハッシュで全エージェント横断の優先度を決定し、同一トレースを全エージェントが一貫して保持/破棄。加重公平キューイングでトリガー ID 間の公平性も保証。 ### トリガー機構(§4.3, 表2) Hindsight はトレースとは独立にトリガーを発火させ、症状検出とトレース収集を分離する。 | トリガー種別 | 動作 | |---|---| | PercentileTrigger(p) | 計測値の p パーセンタイル超過で発火 | | CategoryTrigger(f) | 閾値 f 未満の頻度のカテゴリ値で発火 | | ExceptionTrigger | 例外またはエラーコードで発火 | | TriggerSet(T, N) | トリガー T 発火時に直近 N 件のラテラルトレース ID を含める | TriggerSet によりラテラルトレース(同一キューを共有した他リクエスト群)の捕捉が可能。テイルサンプラーでは traceId ベースのシャーディングが異なるコレクタにルーティングするため、クロストレースの条件を本質的にサポートできない。 ## 実装(§5) - クライアントライブラリ: 約 4 KLOC C(データプレーン効率重視) - エージェント・コーディネータ: 約 5.5 KLOC Go - OpenTelemetry API と互換。X-Trace との統合実績あり。 - ロックフリーの共有メモリキュー(バッチ操作対応)でマルチスレッド書き込みに対応。 ## 評価(§6) ### 93 サービス Alibaba トポロジ(§6.1) 544 コアのプライベートクラスタ(Dell R920 ×10 + M620 ×4)に 93 サービスの MicroBricks(Alibaba トレースデータセット由来)を展開。エッジケース率 1%。 | 構成 | ピークスループット | エッジケース捕捉率 | ネットワーク帯域 | |---|---|---|---| | トレースなし | 14,000 r/s | — | — | | Jaeger 1% ヘッド | ≈14,000 r/s | ≈1%(1.64 件/s) | 1.4 MB/s | | Jaeger テイル(非同期) | 12,000 r/s(−14%) | 低負荷時 100%→高負荷時 <1%(非一貫ドロップ) | 78 MB/s | | Jaeger テイル(同期) | 8,120 r/s(−42%) | ピーク 47 件/s(6,000 r/s 時) | 72.2 MB/s | | **Hindsight** | **≈14,000 r/s(−3.5%)** | **99–100%** | **2.6 MB/s** | ### ユースケース(§6.3) - **UC1 エラー診断**: [[DeathStarBench]] Social Network(12 マイクロサービス)。1–10% のランダム例外注入。ExceptionTrigger でコレクタ帯域内の全例外トレースを一貫的に捕捉。 - **UC2 テイルレイテンシ**: PercentileTrigger(p=99/95/90)で高レイテンシリクエストのみを対象化。ヘッドサンプリングは全分布を無差別に捕捉するのみ。 - **UC3 時間的プロベナンス**: HDFS NameNode キューに QueueTrigger(TriggerSet + PercentileTrigger)を設置。99.99 パーセンタイルキュー遅延の検出時に直前 10 件のラテラルトレースを遡及的に収集。テイルサンプラーでは traceId ベースルーティングのため本質的に不可能。 ### マイクロベンチマーク(§6.4) - 2 サービス MicroBricks で Hindsight は 70.4 k r/s(トレースなし比 −0.9%)。テイルサンプリングは 41.4 k r/s(−41.7%)。 - tracepoint レイテンシ: 32 kB ペイロードで 7.9–8.6 ns(1–8 スレッド)。8B ペイロードで 3.9–4.8 ns。 - begin/end: 70–238 ns(スレッド数に比例、共有メモリキュー競合による)。 - データプレーン書き込みスループット: 最大 55 GB/s。 ## 議論(§7) - **イベントホライズン**: バッファプールサイズ・トレースデータ生成速度・トリガー遅延に依存。10 MB プールでは 500 ms 遅延で一貫性 58%、100 MB プールでは 3 秒遅延で 90% 超。既定 1 GB で約 1 分。 - **トレースパーセンテージ**: 既定 100% だが、オーバーヘッドやメモリ制約がある場合は一貫性ハッシュで全エージェント横断の整合的スケールバックが可能。 - **アプリケーションクラッシュへの耐性**: トレースデータは共有メモリバッファプールに存在するため、アプリケーションプロセスがクラッシュしてもエージェントが継続動作し、バッファプール内データを保全できる。既存フレームワークではアプリケーションメモリ内のバッファが消失する。 ## 位置づけ Hindsight は分散トレーシングのサンプリング問題に対し、「仕組み(どう集めるか)から方針(何を集めるか)への転換」を提唱する。既存のヘッドサンプリング/テイルサンプリングの二項対立を遡及的サンプリングで回避し、エッジケースのための分散トレーシングという本来の用途を実現可能にした。(Source: 本論文 §9)