74. 観測は主役を邪魔しない — リザーバ+固定レートのサンプリングとUDPの割り切り
全リクエストを追わずに、それでも代表的な像を得る——X-Rayのサンプリングと、観測データをアプリの外へ逃がすデーモンの設計を、リクエスト1本がたどる道として図で追っていきます。
① なぜ全数を記録しないのか
- 公式:「効率的なトレースと、アプリケーションが処理するリクエストの代表的なサンプルを提供するために、X-Ray SDKはサンプリングアルゴリズムを適用してどのリクエストをトレースするか決める」。
- デフォルトのサンプリングレートは「getting started で課金が発生しないよう conservative(控えめ)」に設定されている。
記録は無料ではない。サンプリングは「全部見る」を諦める代わりに、コストと負荷を抑えつつ代表的な像を得る割り切りである。
② リザーバ+固定レートの2段構え
- 公式の言い回し:「SDK records the first request each second, and five percent of any additional requests. One request per second is the reservoir. ... Five percent is the rate」。
- レートの書き方:JSON文書では0〜1(=0.05)、コンソールでは0〜100(=5)。
リザーバがあるから低トラフィックでも毎秒1本は必ず残り、レートがあるから高トラフィックでも記録量が線形に膨らまない。「最低保証+超過分は割合で」の2段構えが、記録量を上下から挟む。
③ 記録する側のトークンバケット
- 同じCS基礎(有限資源をバースト枠と定常レートで配分する)の裏表。守る対象が「本番処理のスループット」か「観測データの量」かが違うだけ。
レート制限は捌く側だけのものではない。観測する側も同じ形の仕組みで自分の量を律する——「記録する側のトークンバケット」として読める。
④ ルールは優先度の昇順、最初のマッチで確定
- 公式:「Services evaluate rules in ascending order of priority, and make a sampling decision with the first rule that matches」。
- カスタムルールの優先度は1〜9999の整数。Service name / Service type / Host / HTTP method / URL path 等で絞れる。
- デフォルトルールのリザーバとレートは変更できる(公式には「Reservoir 0・Rate 5」に下げる変更例が載っている)。
ルールは「小さい優先度から順に見て、最初に当たった1本で打ち止め」。だから狭くて重要なルール(決済=priority低い数字)を上に、広い受け皿(デフォルトルール=最後)を下に置く。
⑤ 中央管理とquota、起動直後のborrow
- 公式:「The service manages the reservoir for each rule, and assigns quotas to each instance of your service to distribute the reservoir evenly, based on the number of instances that are running」。
- borrow:「if the reservoir is at least 1, the service borrows one trace per second until X-Ray assigns a quota」。
- 中央管理の利点=「you can manage rules without making additional deployments」(再デプロイ不要でルールを変えられる)。
- リザーバはサービスが直接使う値ではなく、そのルールを使う全サービス合算で効く(collectively)。
台数が変わってもサービスが全体のリザーバを見て配り直すから、合計のサンプリング量が崩れない。quota到着前の空白は「毎秒1本だけ借りる」で埋め、コードは触らずルールだけ差し替えられる。
⑥ 親の決定に従う(parent-based)
- 公式Note:「X-Ray sampling is "Parent-based." ... the sampling decision is made only once, typically by the first X-Ray-enabled service ... a downstream service ... will honor that decision regardless of any of its own matching sampling rules」。
- 落とし穴:BがつねにAから呼ばれるなら、Bのルールは決して適用されない。この経路のサンプリングを変えたいならRoot(A)にルールを書く。
- カスタムルールが効くのは「まだ判定が行われていない場所」=アプリの入口(API Gateway、ロードバランサ、最初の計装済みマイクロサービス)や、新しいトレースを開始する非同期ワーカー。
- ヘッダ例:X-Amzn-Trace-Id: Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1
「記録するか」の判断は入口で一度きり。下流は親のSampledに従うだけ——トレースが1本の単位として一貫し、下流でバラバラに増減しない。だからサンプリングを変えたければRootサービスのルールをいじるのがCS的に正しい。
⑦ デーモンへ、UDPで投げっぱなし
- 公式:「The AWS X-Ray daemon is a software application that listens for traffic on UDP port 2000, gathers raw segment data, and relays it to the AWS X-Ray API」。
- デーモンのログ例に「Successfully sent batch of N segments」とあり、バッチ送信が確認できる。
- Lambdaでは「Lambda runs the daemon automatically any time a function is invoked for a sampled request」(サンプリングされた呼び出しのときデーモンを自動起動)。
- SDK/ADOTがサンプリングAPIを呼ぶときはCloudWatchエージェントをプロキシに使い、こちらはTCPポート2000——セグメント送信のUDP 2000とは別物なので混同しないこと。
観測データはアプリの処理経路の「外」を通す(帯域外)。アプリはデーモンへ投げたら即戻り、遅い送信はデーモンがまとめて肩代わりする。Lambdaではこのデーモンが呼び出しごとに自動で面倒を見る。
⑧ なぜUDPなのか — 保証しないのも設計
- UDPは低遅延・低オーバーヘッドと引き換えに到達保証を持たない(TCP/UDPの使い分けの実例)。
- メッセージング編のat-least-once・可視性タイムアウトが「絶対に落とさない」を守ったのと逆向きの設計判断。観測データは本番リクエストより優先度が低い。
可視性タイムアウトやat-least-onceが「落とさない」を守ったのに対し、観測は「落ちてもよい」を選ぶ。何を保証しないかも設計である——本コースの裏テーマがここで対になる。
⑨ 原理は不変、実装はOpenTelemetryへ
- 公式Note:「On February 25th, 2026, the AWS X-Ray SDKs/Daemon will enter maintenance mode, where AWS will limit X-Ray SDK and Daemon releases to address security issues only. ... We recommend to migrate to OpenTelemetry」。
- ADOTでもX-RayのRemote Sampling(コンソールのルールを読む)がサポートされる。
- CloudWatchエージェント(v1.300025.0以降)はOTel/X-Ray両方のクライアントSDKからトレースを受けてX-Rayへ送れる。現況は執筆時(2026-07)に確認。
ツールの名前は変わっても、このレッスンで見た原理——サンプリングで代表を抜く、観測データを帯域外でバッチ送信する、判定は親に従う——はOTelでもそのまま生きる。学ぶべきは製品名でなく仕組みである。