本文へスキップ
mcpd
デーモンなし
ソース

サンプリング

残すのはトレースの一部です。1 本のトレースの一部ではありません。

判断はルートで一度だけ行われます

トレースは、まるごと残すか、まるごと捨てるかです。判断はルートのスパンが 始まるときに行われ、すべての子に受け継がれるので、実行が半分だけ記録される ことはありません。

他のすべては、この規則から出てきます。スパンのうち無作為な 30% が欠けた トレースは、サンプリングされたトレースには読めません。観測している側の システムの不具合に読めます。実行されなかったように見えるツール呼び出し、 親のないモデル呼び出し、検索があるはずの場所の空白。その空白がエージェント ではなく可観測性の道具のせいだと分かるまでに、午後を 1 つ使うことになります。

既定はすべてを残します

サンプリングを設定しなければポリシーは always で、量が問題に なるまでは、それが正しい既定です。サンプリングは、あなたが後で読みたく なる実行を差し出す取引です。その代価は、ストレージか帯域がそうさせるとき にだけ払ってください。

5 つの戦略

戦略動作
always すべてを残します。既定です。
never 何も残しません。
ratio 一定の割合を残します。ルートで、トレースごとに一度、無作為に引きます。
deterministic 一定の割合を残します。トレース id のハッシュで決めます。どのコレクターも、他のどれとも通信せずに同じ答えにたどり着きます。
tail トレースが終わるまで判断を先送りし、その後は割合の設定にかかわらず、すべてのエラーとすべての遅い実行を残します。

割合を設定する

--sample、または MCPD_SAMPLE は 0.0 から 1.0 の 割合を取り、決定的戦略を設定します。その範囲の外の値は、あなたが渡した値を 示すメッセージとともに、起動時にデーモンを停止させます。範囲に丸めることは しません。打ち間違えた割合が黙って 1.0 になれば、それが分かるのは一か月後、 ストレージの請求書によってだからです。

10 本に 1 本のトレースを残す

mcpd --sample 0.1

どの SDK も同じ割合を読みます。クライアント設定の sample、 または環境変数の MCPD_SAMPLE です。クライアント側の サンプリングのほうが安く済みます。サンプリングされなかったスパンはキューに 入らず、送出もされないので、帯域をまったく使いません。デーモン側の サンプリングは往復分の費用がかかりますが、割合を一か所にまとめられます。 十数個のサービスが 1 つのインスタンスに送っている場合は、そちらが望ましい でしょう。

5 つの戦略のうち、デーモンから届くのは always と deterministic です。--sample と、設定ファイルの プロジェクトの sample は、どちらも deterministic 戦略を設定 します。never、ratio、tail は ポリシーの型の中に実装されていますが、このビルドではフラグからも設定 ファイルからも届きません。

ハッシュで多数のインスタンスの判断がそろう理由

ロードバランサーの後ろで mcpd を複数動かすと、1 つのトレースのスパンが 同じインスタンスに全部届くとはかぎりません。インスタンスごと、あるいは スパンごとにコインを投げるサンプラーは、トレースの一部を残して残りを 捨てます。最初の規則は、まさにその失敗を防ぐためにあります。

決定的戦略は、トレース id を 64 ビットの範囲全体に写し、その値が割合の示す しきい値を下回るときにトレースを残します。どのインスタンスも同じ id から 同じ数を計算するので、共有状態も、調整のためのプロトコルも、ずれる余地も ないまま、全員の判断が一致します。同じ id はリトライでも同じ答えを返すので、 再送されたバッチが半分だけ届くこともありません。

この写像を正直なものにしている細部が、2 つあります。1 つは、id の 末尾 16 桁の 16 進を読むことです。OpenTelemetry はトレース id が 乱数であることを求めていますが、先頭のバイトをタイムスタンプから作る生成側 もあり、そこを読むサンプラーは、サンプリングではなく時刻との相関を取って しまいます。もう 1 つは、id がそもそも 16 進でない場合の動きです。すべてを 残す動作に退化するのではなく、仕上げの撹拌を伴う本物のハッシュに フォールバックするので、実際の割合は、あなたが指定した割合の近くに とどまります。

SDK では上流の判断が優先されます

SDK が受け取った W3C の traceparent からトレースを続ける場合、 ID と一緒に sampled フラグを引き継ぎ、自分の割合は適用しません。これは 両方向に効きます。フラグが立っていればローカルの割合に関係なくトレースは 残され、フラグが下りていればローカルの割合に関係なく捨てられます。

このビルドのデーモンはこれを行いません。OTLP で届いたスパンについて、 デーモンはその trace-flags バイトを属性 mcpd.otlp.flags に 残しますが、デーモンのサンプラーはそれを読みません。割合を設定したデーモンは、 フラグが何を示していても、すべてのトレースにその割合を適用します。

そうしない場合の結果は、字面から受ける印象より深刻です。各サービスが自分の 割合を適用すれば、4 つのサービスをまたぐトレースは、2 つで残されて 2 つで 捨てられます。最後に手元に残るのは、分散トレースではありません。分散トレース の形をした穴の集まりです。

テールサンプリングは、読む価値のある実行を残します

ヘッドサンプラーは、何も分からないうちに判断します。安上がりですが、目が 見えていません。10 分の 1 なら、失敗も 10 分の 1 しか残しません。あなたが実際に 開くトレースはめったに起きないほうであり、めったに起きないものこそ、割合に よるサンプラーが最も苦手とするものです。

A strip chart recording model latency over the last hour: a baseline near 420 milliseconds with five occasional excursions towards 800 milliseconds.

レイテンシの記録は、こういう見た目になります。平らな基準線と、いくつかの 逸脱です。量があるのは基準線のほうで、答えがあるのは逸脱のほうです。テール サンプリングはトレースが終わるまで保持し、その中で何かがエラーになって いれば残し、あなたが設定したしきい値より長く走っていれば残し、それ以外には 先ほどと同じ決定的ハッシュを適用します。エラーを残す動作は既定で有効です。 いちばん必要になるトレースはめったに起きないものであり、割合によるサンプラー は、それをいちばん捨てやすいからです。

代価はバッファリングです。テールサンプラーは、判断できるようになるまで、 終わっていないトレースをすべてメモリーに保持しなければなりません。だから これは既定ではなく、意図して選ぶものです。上に書いたとおり、テール戦略は ポリシーの型の中に実装されており、このビルドではフラグからも設定ファイル からも届きません。デーモンの取り込み経路が適用するのは、ヘッドの判断です。

何が捨てられたかを知る

サンプラーが捨てたスパンは、そのつど mcpd_traces_sampled_out_total を増やします。この値は /metrics に Prometheus のテキスト形式で出ています。割合は、 チームが読む場所に書いておいてください。サンプリング率が文書化されていれば、 トレースが無いことには説明が付きます。説明の無いトレース欠落はサポート依頼 になり、それを書くのは、たいていあなた自身です。

次に

  • 保存する量を減らす、もう 1 つの方法: 秘匿化と保持期間。
  • すべてのフラグと環境変数: 設定。
  • /metrics と、デーモン自身のそのほかのシグナルを読む: 運用。