Dev Study
AWSサービスの内部原理 コース

74. 観測は主役を邪魔しない — リザーバ+固定レートのサンプリングとUDPの割り切り

全リクエストを追わずに、それでも代表的な像を得る——X-Rayのサンプリングと、観測データをアプリの外へ逃がすデーモンの設計を、リクエスト1本がたどる道として図で追っていきます。

① なぜ全数を記録しないのか

大量のリクエスト毎秒ひっきりなしに到着
全数トレースコストがトラフィックに比例・データ量が線形爆発
サンプリング代表を抜き出し、傾向は保ったまま量を抑える
✗ 主役を圧迫観測が本番リクエストの負荷になる
✓ 脇役に徹する観測は本番を邪魔しない
  • 公式:「効率的なトレースと、アプリケーションが処理するリクエストの代表的なサンプルを提供するために、X-Ray SDKはサンプリングアルゴリズムを適用してどのリクエストをトレースするか決める」。
  • デフォルトのサンプリングレートは「getting started で課金が発生しないよう conservative(控えめ)」に設定されている。

記録は無料ではない。サンプリングは「全部見る」を諦める代わりに、コストと負荷を抑えつつ代表的な像を得る割り切りである。

② リザーバ+固定レートの2段構え

この1秒の到着列毎秒ごとにふるい分け
リザーバを使い切った残り
段1: リザーバ毎秒 最初の1本は必ず記録
最低保証
ふるいを通過した分だけ
段2: 固定レート残りのうち5%だけ記録・外れは捨てる
超過分は割合で
記録量が確定最低1本+超過分の5%
  • 公式の言い回し:「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段構えが、記録量を上下から挟む。

③ 記録する側のトークンバケット

トークンバケットAPI Gateway編で既習
サンプリングX-Rayの2段構え
バケット容量= バースト枠
リザーバ= 毎秒の最低保証(1本)
補充レート= 定常処理量
固定レート= 超過分の割合(5%)
捌く量を守る本番処理のスループットが対象
記録量を守る観測データの量が対象
  • 同じCS基礎(有限資源をバースト枠と定常レートで配分する)の裏表。守る対象が「本番処理のスループット」か「観測データの量」かが違うだけ。

レート制限は捌く側だけのものではない。観測する側も同じ形の仕組みで自分の量を律する——「記録する側のトークンバケット」として読める。

④ ルールは優先度の昇順、最初のマッチで確定

リクエスト到着
no-match
priority=1決済API /payment/*
match → レート100%で確定
no-match
priority=100ヘルスチェック /health
match → レート0%で確定
ここまでで必ず決まる
デフォルトルールどれにもマッチしなかった残り全部の受け皿(最後に評価)
リザーバ1本+5%
記録する/しない最初にマッチした1つだけが効く
  • 公式:「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

X-Rayサービスルールとリザーバを一元管理
インスタンスAquota割当済み
インスタンスBquota割当済み
インスタンスC起動直後・quota未割当
quota内で記録
quota内で記録
borrowreservoir≥1なら毎秒1本を借りる
quota到着まで
  • 公式:「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)

Service A = Root入口でサンプリング判定を1回だけ実施
Sampled=1 に決定
Sampled=1 を伝播
Service B自前の「厳しいルール」を持っていても……
✗ Bのルールは発火しない(既に決定済み)
Service Cやはり親の決定 Sampled=1 に従う
  • 公式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で投げっぱなし

アプリ+SDKセグメントを生成
ある程度たまったらバッチにまとめて送信
X-Rayデーモン別プロセス。受け取ったセグメントをバッファ
X-Ray APIトレースとして保存
  • 公式:「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なのか — 保証しないのも設計

メッセージング編SQS等
X-Ray送信SDK→デーモン
at-least-onceTCP的。可視性タイムアウトで再配信
UDPで送りっぱなし応答を待たない・再送しない
落とさない守るもの=データの完全性
落ちてもよい守るもの=アプリの低遅延
  • UDPは低遅延・低オーバーヘッドと引き換えに到達保証を持たない(TCP/UDPの使い分けの実例)。
  • メッセージング編のat-least-once・可視性タイムアウトが「絶対に落とさない」を守ったのと逆向きの設計判断。観測データは本番リクエストより優先度が低い。

可視性タイムアウトやat-least-onceが「落とさない」を守ったのに対し、観測は「落ちてもよい」を選ぶ。何を保証しないかも設計である——本コースの裏テーマがここで対になる。

⑨ 原理は不変、実装はOpenTelemetryへ

X-Ray SDK/デーモン2026-02-25 メンテナンスモードへ
以降はセキュリティ修正のみ
原理はそのまま生きる
OpenTelemetryADOT / CloudWatchエージェント
サンプリングリザーバ+固定レート・remote sampling
帯域外バッチ送信collector/agent経由
parent-based判定は親に従う
  • 公式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でもそのまま生きる。学ぶべきは製品名でなく仕組みである。

公式ドキュメントで詳しく ↗