Skip to main content

TMP ルーター

TMP ルーターは、パブリッシャーとバイヤーエージェントの間に位置するインフラです。リクエストのファンアウト、レスポンスのマージ、プライバシー強制を扱います。決定を下しません — リクエストをルーティングしレスポンスを集約します。パブリッシャーはルーターがどのプロバイダーを呼ぶかを設定します。

ルーターがすること

  1. リクエストをファンアウトする: context_match ケイパビリティを持つ設定されたすべてのプロバイダーに Context Match リクエストを送る。identity_match ケイパビリティを持つ設定されたすべてのプロバイダーに Identity Match リクエストを送る。
  2. レスポンスをマージする: 複数のプロバイダーからのオファー、エンリッチメントシグナル、適格性結果を統一されたレスポンスに結合する。
  3. 分離を強制する: コンテキストとアイデンティティのコードパスは構造的に分離 — コンテキストパスは決してアイデンティティデータにアクセスせず、逆も同様。
  4. レイテンシーを管理する: 適応的タイムアウトを適用し、一貫してレイテンシー予算を超えるプロバイダーを非優先化する。

単一バイナリ、分離されたコードパス

ルーターは 2 つの構造的に分離されたコードパスを持つ単一の Go バイナリです: 1 つは context match 用、1 つは identity match 用。
分離はコードの中にあり監査可能です。コンテキストパスは、アイデンティティデータが渡されず、到達可能などの場所にも保存されず、コンテキストパスが処理するどのデータ構造でも参照されないため、それを読めません。アイデンティティパスには逆が同じように適用されます。ルーターはオープンソースです — 誰でもソースを読んでこれを検証できます。 TEE アテステーションはアップグレードパスです。TEE なしでは、オペレーターが公開されたバイナリをデプロイしたことを信頼します。TEE ありでは、アテステーションがデプロイされたバイナリが監査されたソースに一致することを証明し、その信頼要件を除去します。

プロバイダー登録

パブリッシャーはルーターがどのプロバイダーを呼ぶかを設定します。これは運用上の関係です — パブリッシャーはプロバイダーが自身の広告決定に参加することを信頼します。プロバイダー登録は provider-registration スキーマ(/schemas/trusted-match/provider-registration.json)に従います。

ディスカバリーモデル

プロバイダー登録は通常 ページ設定 から来ます — パブリッシャーは Prebid モジュール設定またはサーフェス固有のセットアップでプロバイダーを宣言します。これが標準パスで、安定したプロバイダーセットを持つパブリッシャーにうまく機能します。 静的設定(Prebid config、YAML ファイル、infrastructure-as-code):
  • パブリッシャーがデプロイ時にプロバイダーを宣言
  • ルーターが起動時と設定リロード時に設定を読む
  • 変更には設定更新とリロード/再デプロイが必要
  • ほとんどのデプロイに適切 — プロバイダーリストはめったに変わらない
動的登録(API 駆動、データベース裏付け):
  • パブリッシャーが管理インターフェースを通じてプロバイダーを管理
  • ルーターがディスカバリーエンドポイントをポーリングするか設定変更を監視
  • 変更は 1 リフレッシュサイクル内に有効になる(推奨: 30 秒)
  • 多くのプロバイダーを管理するか、再デプロイなしのランタイム更新が必要なパブリッシャーに適切
  • 動的登録エンドポイントは、プロバイダー endpoint URL が外部 HTTPS アドレスであることを検証しなければならない(MUST)。実装は、プロバイダー登録を通じた SSRF を防ぐため、プライベート(RFC 1918)、リンクローカル(169.254.x.x)、クラウドメタデータの IP 範囲を拒否しなければならない(MUST)。完全な規範的要件 — エンドポイント URL 検証(DNS 再解決を伴う)、動的登録エンドポイント認証、ルーター対プロバイダー認証の最低ライン、/health エンドポイントガイダンス — については仕様の プロバイダー登録セキュリティ を参照。
両モデルは同じスキーマを使います。ルーターは YAML ファイルからロードされたプロバイダーと API からロードされたプロバイダーを区別しません — 登録フィールドは同一です。

登録フィールド

context_match または identity_match の少なくとも一方が true でなければなりません — どちらの操作も扱わないプロバイダーは無効です。identity_match が true のとき、countriesuid_types必須 です — ルーターはそれらなしに Identity Match リクエストをルーティングできません。ルーターは無効なプロバイダー登録を拒否しなければならず(MUST)、誤設定されたプロバイダーを識別する警告をログすべきです(SHOULD)。

プロバイダーライフサイクル

プロバイダーは 3 つのライフサイクル状態を持ちます:
  • Active: プロバイダーが通常どおりリクエストを受け取る。
  • Draining: プロバイダーが新しいリクエストの受け取りを停止する。飛行中のリクエストは通常どおり完了する。プロバイダーを保守のためオフラインにするとき使う。
  • Inactive: プロバイダーが完全にスキップされる。設定を削除せずにプロバイダーを無効化するとき使う。

プロバイダーヘルス

プロバイダーはそのベース URL で GET /health を公開すべきです(SHOULD)。ルーターはこれを次に使います:
  • プリフライトチェック: 起動時または設定リロード時に、ファンアウトに含める前に各プロバイダーが到達可能であることを検証。
  • 定期監視: 設定可能な間隔(推奨: 30 秒)でプロバイダーヘルスを確認。連続するヘルスチェックに失敗するプロバイダーは、一時的にファンアウトから除外され(MAY)、ヘルスが回復したとき自動的に再包含される。
ヘルスチェックはリクエストのホットパスにはありません — バックグラウンド間隔で実行されます。ルーターの /healthz エンドポイントは、個々のプロバイダーステータスではなく全体的なルーターヘルスを反映します。 プロバイダーは context_matchidentity_match の任意の組み合わせをサポートしてもよい(MAY)。コンテキストのみのプロバイダーはエンリッチメントまたはコンテキストターゲティングを扱います。アイデンティティのみのプロバイダーはフリークエンシーキャッピングを扱います — パブリッシャーはメディアバイのターゲティングルールからコンテキストをローカルで評価し、アイデンティティチェックのためだけにバイヤーを呼びます。 すべての通信は HTTP/2 上の JSON を使います。TMP メッセージは小さい(200-600 バイト) — これらのサイズでは、シリアライゼーション形式は総レイテンシーの 1% 未満です。

統合

Prebid 統合

Prebid Server または Prebid.js を持つパブリッシャーは、ベンダー固有の RTD モジュールを置き換える TMP モジュールを追加します。TMP モジュールは Context Match と Identity Match リクエストをルーターに送り、マージされたレスポンスをターゲティングシグナルとパッケージアクティベーションデータとして返します。パブリッシャーのアドサーバー(GAM など)はターゲティングキー値を受け取り、対応するラインアイテムをアクティベートします。

非 Prebid サーフェス

AI アシスタント、モバイルアプリ、CTV、リテールメディアについては、ルーターは直接 HTTP/2 API を提供します。HTTP/2 POST リクエストを行える任意のプラットフォームが統合できます。リクエストとレスポンスのスキーマはサーフェスにかかわらず同じです。

SSP と DSP 統合

SSP と DSP は TMP プロバイダーとして統合します — ファンアウト中にルーターが呼ぶエンドポイントを公開します。これは既存の RTD 統合と同じパターンです。

アイデンティティトークン

アイデンティティトークンは、既にページ上またはアプリ内に存在する既存のプロバイダー(ID5、LiveRamp、UID2 など)から来ます。TMP はトークンのライフサイクルを仕様化しません — パブリッシャーのアイデンティティスタックが既に生成するトークンを消費します。

ファンアウトとレスポンスマージ

Context Match ファンアウト

パブリッシャーが Context Match リクエストを送るとき:
  1. ルーターはリクエストの property_rid について context_match ケイパビリティで設定されたすべてのプロバイダーを識別する。
  2. HTTP/2 上で一致するすべてのプロバイダーに並列でリクエストを送る。
  3. レイテンシー予算(デフォルト: 50ms)までレスポンスを待つ。
  4. レスポンスをマージする:
    • オファー はすべてのプロバイダーから収集される。2 つのプロバイダーが同じ package_id のオファーを返す場合(まれ — パッケージは通常プロバイダー固有)、ルーターは最初に受け取ったレスポンスを保持する。プロバイダーをまたいだ重複する package_id は設定エラー。ルーターは警告をログすべき(SHOULD)。
    • エンリッチメントシグナル は連結される。すべてのプロバイダーからのセグメントが単一のリストに結合される。異なるプロバイダーからのターゲティングキー値は衝突を防ぐため名前空間化される。
  5. マージされたレスポンスをパブリッシャーに返す。

Identity Match fan-out

ルーターは国とアイデンティティタイプで Identity Match プロバイダーをフィルターします:
  1. ルーターはリクエストから country フィールド(アイデンティティシグナルではなくルーティングディレクティブ)を読む。
  2. countries リストがその国コードを含むプロバイダーを選択する。
  3. さらに、uid_types リストがリクエストの identities 配列の任意の uid_type と重なるプロバイダーにフィルターする。
  4. 選択された各プロバイダーについて、identities 配列をフィルター して、リクエストのアイデンティティとそのプロバイダーの宣言された uid_types の交差にする。プロバイダーは宣言しなかったタイプのアイデンティティトークンを受け取ってはならない(MUST NOT) — これは minimum-necessary-data を運用上のものではなく構造的なプライバシープロパティとして強制する。ルーターはアイデンティティトークンを追加、置換、変換してはならない(MUST NOT)。転送されたセットはパブリッシャー起源の identities 配列のサブセットでなければならない(MUST)。
  5. 交差が空の場合、ルーターはそのプロバイダーを完全にスキップしなければならない(MUST)。空の identities 配列は有効な IMR ペイロードでなく(スキーマが minItems: 1 を強制)、skip 対 forward を区別可能なテレメトリとして発することは、各ユーザーがどのアイデンティティタイプを利用可能だったかを漏らす。
  6. バイヤーエージェントにリクエストを転送する前に country フィールドを剥がす
  7. プロバイダーごとのペイロードがインバウンドリクエストと異なるため、ルーターはフィルターされたセットの正準署名フィールド — identities_hash(アイデンティティごとの attestation をカバー)と、存在するとき audience_kid によってそのプロバイダーにルーティングされた sealed_credentials[] エントリの sealed_credentials_hash — に対して各プロバイダーごとの転送を 再署名 する(Identity Match signed fields で定義)。プロバイダーはルーターの公開鍵に対して署名を検証する。
  8. 一致するすべてのプロバイダーに並列でファンアウトし、適格性結果をマージし、統一されたレスポンスを返す。
プロバイダーをまたいだ重複する package_id は設定エラーです — パッケージはメディアバイから来てプロバイダー固有です。発生した場合、ルーターは保守的なマージを適用します: パッケージは両方のプロバイダーの eligible_package_ids に現れるときのみ適格。ルーターはプロバイダーをまたいだ最小の serve_window_sec を使い、警告をログすべき(SHOULD)。 TMPX 収集。 TMPX トークンを鋳造するのに十分なアイデンティティ素材を解決する各アイデンティティプロバイダーは、その順序付けられたマクロ/値ペアを tmpx_macros[] で返します — { name, value } のペアで、name はプロバイダーの登録された tmpx_macros スロット(provider-registration.json)の 1 つ、value は URL セーフなワイヤー文字列です。ルーターはそれらのエントリを、発行プロバイダーの provider_id でキー付けされたレスポンスの tmpx_providers マップに収集しなければならず(MUST)、プロバイダーごとのインプレッション会計がファンアウトを生き残るようにします。ルーターはプロバイダーのペア順を逐語的に保持しなければならず(MUST) — チャンクは決定論的 — 複数のプロバイダーの値を単一の tmpx 文字列に折り畳んではなりません(MUST NOT)。ルーターは provider_id からマクロ名を合成してはなりません(MUST NOT)。トラフィッキングは事前に登録された名前に対して設定されます。ルーターはアウトバウンドレスポンスのルートに tmpx_macros を運んではなりません(MUST NOT) — そのフィールドはプロバイダー→ルーターのキャリアです。tmpx_providers と並んでそれを漏らすと、パブリッシャーにどれを読むべきかのスキーマシグナルを与えず、同じ値を 1 つのスロットに二重発火するリスクがあります。任意の TMPX を発しないプロバイダー(例: 適格なパッケージなし)は、空の macros[] で表現されるのではなくマップから省略されなければなりません(MUST)。非推奨の単数 tmpx フィールドを読むコンシューマーとの後方互換性のため、ルーターは 1 つのプロバイダーの最初のスロット値で tmpx も投入してもよい(MAY)。両方のフィールドが存在するとき、tmpx_providers が権威的です。

タイムアウト処理

ルーターは 2 つの明確なタイムアウト値を管理します:
  • 全体レイテンシー予算latency_budget_ms): ルーターがファンアウトし、レスポンスを収集し、マージする総時間。デフォルト: 50ms。これはパブリッシャーが広告配信パイプライン内で TMP に割り当てるエンドツーエンドの予算。
  • プロバイダーごとのタイムアウト(プロバイダー登録の timeout_ms): ルーターが単一のプロバイダーを待つ最大時間。全体レイテンシー予算以下でなければならない。デフォルト: 50ms(単一プロバイダー設定では予算と等しい)。
複数のプロバイダーが設定されるとき、プロバイダーごとのタイムアウトが各個別プロバイダーの実効上限で、全体予算がファンアウト全体の上限です。ルーターは各プロバイダーについて 2 つのうちより厳しい方を強制します。例えば: 50ms の全体予算と各 40ms に設定された 2 つのプロバイダーで、両プロバイダーが並列に呼ばれ、ルーターは合計で最大 50ms 待ちます — プロバイダー A が 45ms で応答すると、プロバイダー B は既に 40ms でタイムアウトしています。
  • 単一プロバイダータイムアウト: そのプロバイダーをスキップし、そのレイテンシーパーセンタイルをログし、残りのプロバイダーからのレスポンスで続行。スキップされたプロバイダーのパッケージはこのリクエストについて「アクティベートされない」として扱われる。
  • すべてのプロバイダータイムアウト: 空のレスポンスを返す — Context Match のオファーなし、Identity Match の適格性なし。パブリッシャーは既存の需要ソース(Prebid オープンオークション、直接販売など)にフォールバックする。
  • 適応的タイムアウト: ルーターはプロバイダーごとのレイテンシーパーセンタイル(p50、p95、p99)を追跡し、時間をかけて割り当てを調整する。一貫して遅いプロバイダーはより小さいタイムアウト割り当てを受けるか先制的にスキップされる。適応的割り当てがアクティブなとき、より高優先のプロバイダー(低い priority 値)は予算のより大きなシェアを受ける。これは運用上の決定であり、プロトコル要件ではない。

レイテンシー予算

TMP は 50ms 未満のエンドツーエンドレイテンシーをターゲットにします: パブリッシャーがリクエストを送り、ルーターがファンアウトし、プロバイダーが応答し、ルーターがマージし、パブリッシャーがレスポンスを受け取る。 これが達成可能なのは:
  • 小さいメッセージ: TMP リクエストは 200-600 バイトの JSON — 典型的な OpenRTB 入札リクエストのおよそ 10-20 倍小さい。シリアライゼーションはマイクロ秒未満。
  • 価格計算なし: パッケージは事前交渉済み。プロバイダーはオークションダイナミクスではなくターゲティング基準を評価する。
  • 並列ファンアウト: すべてのプロバイダーが同時に呼ばれる。総レイテンシーは合計ではなく最も遅いプロバイダーの応答時間。
  • ステートレスルーター: ホットパスにデータベースルックアップなし。ルーターの唯一の仕事は転送とマージ。
  • 接続再利用: HTTP/2 多重化により、単一の接続で各プロバイダーへの並行リクエストが可能。

ベンダー RTD モジュールとの比較

TMP ルーターは、ベンダー固有の RTD モジュールが今日することを一般化します。単一ベンダーの RTD モジュールはコンテンツに対してパッケージをリアルタイムで評価しますが、1 つのプロバイダー、1 つのサーフェス(Prebid)にロックされ、完全な OpenRTB BidRequest を送ります。 TMP ルーターはこれをマルチプロバイダー、マルチサーフェス、プロトコル標準の代替に置き換えます: 既存の Prebid Server デプロイについて、TMP モジュールはベンダー固有の RTD モジュールを汎用 TMP クライアントに置き換えます。Prebid のないサーフェスについて、ルーターの HTTP/2 API が同じ機能を提供します。

TEE オークションインフラとの関係

TEE ベースのオークションインフラ(暗号化された入札、アテステーション証明、検証可能な勝者選択)は TMP と補完的です。パブリッシャーが複数のバイヤーからのアクティベートされたパッケージ間で競争的選択を望むとき:
  1. TMP ルーターが Context Match レスポンス(各バイヤーがアクティベートしたいパッケージ)を収集する。
  2. パブリッシャーがアクティベートされたパッケージ(事前交渉された価格付き)を TEE オークションに提出する。
  3. TEE エンクレーブが勝者を選択しアテステーション証明を生成する。
  4. パブリッシャーが勝ったパッケージをアクティベートする。
TMP はマッチングを扱います。TEE オークションは競争を扱います。パブリッシャーはそもそも競争が必要かを選びます — 多くのサーフェス(編集 AI コンテンツ、CTV ポッド構成、リテールカルーセル)は、価格ベースのオークションよりパブリッシャー側の関連性ランキングによってよりよく提供されます。 TEE オークションインフラ(AWS Nitro Enclaves、アテステーション、鍵管理)は、TMP ルーターを TEE アテスト済み運用にアップグレードするとき直接適用可能で、プロトコルの自然なインフラパートナーになります。

Deployment

TMP ルーターは adcp-go 上に構築された単一の Go バイナリです。プロバイダーとそのケイパビリティをリストする設定ファイルを読みます。各プロバイダーはそのベース URL の下に 2 つのパスベースのエンドポイント — POST /contextPOST /identity — を公開し、ルーターはパスでディスパッチします。

設定

コンテナデプロイ

ルーターはステートレスです — データベースなし、永続ストレージなし。任意のロードバランサーの背後で水平スケールできます。ヘルスチェックは /healthz で利用可能です。

キャパシティプランニング

各ルーターインスタンスは、2-vCPU コンテナで毎秒約 10,000 リクエストを扱います。メモリ使用量は、リクエストボリュームではなく、プロバイダーへの並行接続数に線形にスケールします。 Web パブリッシャーには、point of presence(PoP)ごとに 1 つのルーターインスタンスが典型的です。AI プラットフォームには、ルーターがエンドツーエンドレイテンシーに 5ms 未満を追加するため、地域フェイルオーバーを伴う中央集権デプロイで十分です。

監視

ルーターは /metrics で Prometheus メトリクスを公開します: tmp_provider_timeout_total の増加でアラート — 一貫してタイムアウト予算を超えるプロバイダーは、それを含むすべてのリクエストのマッチ品質を劣化させます。