アーキテクチャ (IT)システムアーキテクト

百行以上の異種需要側プラットフォームにわたる100ms未満のオークション決定を調整する、プラネタリースケールのリアルタイムプログラマティック広告交換を設計してください。キャンペーンごとの予算ペーシングを分散ロックなしで強制し、リクエストパス内の行動指紋を通じてクリック詐欺を検出し、不変の台帳エントリを介して請求不一致を調整しながら、GDPR準拠の地域データ主権を維持します。

Hintsage AIアシスタントで面接を突破

質問への回答

質問の歴史

初期の広告配信は、出版社が需要パートナーを順番に優先する静的な滝構成に依存しており、レイテンシーボトルネックと収益漏れを引き起こしていました。「ヘッダービディング」や「OpenRTB」プロトコルへのシフトは、インベントリアクセスの民主化を図りましたが、100ms以内でオークションを完了する必要があるという極端なエンジニアリング制約を導入しました。予算の強制は数千のエッジノードでの過剰支出を防がなければならず、詐欺検出はネットワークホップを追加せずにインラインで行われなければなりません。この質問は、集中型の「Apache Kafka」パイプラインを、財務的決定を自律的に行うことが可能なエッジコンピューティングアーキテクチャに置き換える必要から生まれました。

問題

従来のアーキテクチャは、予算カウンターやフィーチャーストアのために集中型の「PostgreSQL」または「Redis」クラスターに依存しており、トラフィックの急増時(例:ブラックフライデー)に100msのSLAを侵害するクロスリージョンのレイテンシーを生じさせます。予算減少時の素朴な楽観的ロックはサンダリングハードと落札の喪失を引き起こし、非同期の詐欺検出によりボットがキャンペーン予算を尽くす前に検出がトリガーされます。さらに、DSP(需要側プラットフォーム)間の請求調整は、イメージピクセルが発火するが受領メッセージが落ちるネットワークパーティショニングのために苦しみ、収益漏れや重複請求を引き起こし、広告主の信頼を損ないます。

解決策

「Envoy Proxy」サイドカーと「WebAssembly」フィルターをエッジの「PoP」(Presence Point)にデプロイして、エンドユーザーから10ms以内でオークションロジックを実行します。「Redis」を使用して「CRDT」(Conflict-free Replicated Data Type)カウンターを実装し、「Gossipプロトコル」で予算ペーシングを行い、エッジノードがローカルで入札を受け入れながら、最終的な収束を通じてグローバル予算一貫性を確保します。エッジ層内に軽量の「TensorFlow Lite」モデルを埋め込み、マウス速度パターンやナビゲーションエントロピーなどの行動指紋を使用してリアルタイムのボット検出を行います。「Apache Pulsar」を「Geo-Replication」と「BookKeeper」で使用して不変の監査ログを作成し、イデンプタントプロデューサーと重複除去ウィンドウを介して正確一次セマンティクスを保証します。GDPR準拠のために、「K-匿名性」チェックと「Anycast DNS」によるデータ居住経路を実装し、「EDNSクライアントサブネット」に注意を払いましょう。

実生活からの状況

2023年のブラックフライデーイベント中に、私たちのプラットフォームはトラフィックが40倍に急増し、集中型の「Redis」予算ストアが「us-east-1」で飽和状態になり、12%のオークションがタイムアウトし、200万ドルの潜在的な収益損失の脅威がありました。エンジニアリングチームは重要なアーキテクチャの決定に直面しました:強い一貫性を維持し、レイテンシー違反を受け入れるのか、それともスピードを優先し、予算の過剰支出のリスクを冒すのか。

解決策A: Redlockを使用したRedisクラスタ

私たちは、予算の一貫性を厳守するために5つの独立した「Redis」マスターノード全体に「Redlock」アルゴリズムを実装することを検討しました。このアプローチは理論的には、各減少に対して過半数の合意が必要であるため、どのキャンペーンも1日の上限を超えないことを保証するとされていました。しかし、エッジノードとRedisクラスタ間の往復時間は35msで、負荷がかかるとロックの競合により8%のリクエストが複数回再試行され、100msのSLAを超えてしまいました。このアプローチは予算の正確な管理を提供しましたが、受け入れられないレイテンシーと運用の複雑さがリアルタイム入札には不適切でした。

解決策B: ローカルインメモリキャッシングと非同期同期

代わりに、各エッジノードが完全にローカルな予算カウンターを維持し、30秒ごとに中央台帳に非同期で同期をとることを許可することを評価しました。これにより、5ms未満のオークションレイテンシーを達成し、外部依存関係なしにトラフィックの急増に優雅に対応しました。しかし、急増中に複数のエッジノードが高額なキャンペーンを合計80万ドルオーバーシュートしてしまい、同期が発生する前に発生してしまいました。速度は最適でしたが、財務リスクは支払いに関連するシステムにとって壊滅的でした。

解決策C: 階層型ペーシングを伴うハイブリッドCRDTアーキテクチャ

「Redis」の3層で「Delta-State CRDT」を使用したハイブリッドアプローチを実装しました:エッジ、リージョナル、グローバル。エッジノードは、グローバルな予算の95%に制限された保守的なローカルしきい値を持つローカル「PN-Counters」(正負カウンタ)を使用して入札を受け入れます。ローカル予算が尽きると、ノードは「Read-Your-Writes」一貫性をもって地域キャッシュにクエリを送ります。残りの5%のバッファは、ゴシップ同期中のCRDTマージを使用してグローバル台帳によって管理されます。詐欺対策として、私たちはネットワークコールなしでボットパターンを検出するように訓練されたTinyMLモデルをエッジノードに展開しました。この解決策を採用したのは、99.9%の予算正確性を維持しながらp99レイテンシーを45msに保つことができたからです。

結果

プラットフォームはピーク時に毎秒1200万のクエリを処理し、制限されたキャンペーンでの予算のオーバーシュートが一切ありませんでした。詐欺検出レイテンシーは150msから8msに低下し、入札提出前に3.4%の悪意のあるトラフィックをブロックしました。CRDT調整は地域間で200ms内に最終的一貫性を達成し、請求調整ウィンドウ内に収まり、GDPR準拠はエッジローカルデータ処理を通じて維持されました。

候補者が見逃すことが多いこと

どのようにして複数のエッジノードが同時にキャンペーン予算を減少させる際に、グローバルロックを取得せずに予算のオーバーシュートを防止しますか?

ほとんどの候補者は分散ロックやRedisでの原子的減少操作を提案しますが、これらはネットワークパーティショニングや高レイテンシー下で失敗します。正しいアプローチは、CRDTとして実装されたPN-Counters(正負カウンター)を使用します。各エッジノードは、支出のローカルインクリメントカウンターと、払い戻しのための減少カウンターを維持します。ノードが入札を受け入れる際、ローカル支出カウンターを増加させます。ゴシップ同期中、ノードはそのカウンターステートを交換し、カウンターコンポーネントの最大値を取る「Join」操作を使用してマージします。一時的なオーバーシュートを防ぐために、保守的な上限を持つ「トークンバケット」アルゴリズムをローカルに実装します。すべてのローカル支出の合計がグローバル制限に近づくと、ノードは地域コーディネーターに残りの5%の予算を問い合わせます。これにより、パーティション中に理論的に1-2%の一時的オーバーシュートが可能であっても、システムは予算の105%を超えることは決してありません。これは、従来の銀行システムとは異なり、デジタル広告のSLAには許容されるものです。

ユーザーブラウザからインプレッション追跡ピクセルが発火するが、ネットワーク障害によりオークションサーバーへの応答を受け取れない場合、どのようにして正確に1回の請求を保証しますか?

候補者はしばしば「Kafka」のイデンプタント性やデータベースのアップサートを提案しますが、エンドツーエンドの問題を見落とします。この解決策は、クリエイティブマークアップに埋め込まれた「UUIDv7」(時間順)で生成されたイデンプタントキーをエッジで使用する必要があります。ブラウザがインプレッションピクセルを発火すると、このキーが含まれます。エッジの「Nginx」層は「Apache Pulsar」に書き込み、24時間ウィンドウで重複除去を有効にします。「Pulsar」の「BookKeeper」ストレージは、同じキーでの重複書き込みが消費者レベルではなく、ブローカーのレベルで破棄されることを保証します。さらに、イデンプタントキーによってパーティションされた「BigQuery」ステージングテーブルに「少なくとも1回」の配信を実装し、ETLプロセス中に重複除去を行う「MERGE」ステートメントを使用します。この二重保護により、ブラウザが500エラーのためにピクセル発火を50回再試行しても、広告主は正確に1回請求されます。

応札者が地理的に分散している際に、オークションの勝者を決定するために応答時間に基づいて時計のずれをどのように扱いますか?

これは微妙な問題です。候補者はしばしば「NTP」や「TrueTime」(「Spanner」から)を提案しますが、これらはレイテンシーを追加します。正しいアーキテクチャは、オークションロジックから壁時計の依存性を取り除きます。DSPの応答からタイムスタンプを比較するのではなく、エッジで「論理時計」(Lamportタイムスタンプ)を使用するか、単にFIFOキューを使用します。オークションが開始されると、エッジノードは「高解像度タイマー」(V8のPerformance.now()またはC++のchrono)を開始します。DSPの応答はタイムスタンプヘッダーではなく、ネットワークインターフェースでの到着順序によってランク付けされます。遅延応答を処理するために、DSPごとの過去のp99レイテンシーに基づいて調整される「調整可能なタイムアウト」を実装します。請求に関する異議申し立てや事後分析のために、「単調時計」の読み取りと不確実性の間隔を持つ「UTCタイムスタンプ」を記録し、それらを「CockroachDB」に保存します。不確実性ウィンドウを自動的に処理します。これにより、あるDSPのサーバーの時計が他のサーバーより200ms早い場合でも、公平性が確保されます。