Architecture systèmeArchitecte Système

Concevez un échange publicitaire programmatique à l'échelle planétaire et en temps réel qui orchestre des décisions d'enchères en moins de 100 ms à travers des plateformes du côté de la demande hétérogènes, applique un rythme budgétaire par campagne sans verrouillage distribué, détecte la fraude au clic par des empreintes comportementales dans le chemin de demande et réconcilie les écarts de facturation par des entrées de registre immuables tout en maintenant la souveraineté des données régionales pour se conformer au RGPD.

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse à la question

Historique de la question

Les premières publicités reposaient sur des configurations en cascade statiques où les éditeurs donnaient la priorité aux partenaires de demande séquentiellement, créant des cascades de latence et des fuites de revenus. Le passage aux Enchères en Entête et aux protocoles OpenRTB a démocratisé l'accès à l'inventaire mais a introduit des contraintes d'ingénierie extrêmes : les enchères doivent être terminées en moins de 100 ms pour éviter l'abandon de page, l'application stricte des budgets doit prévenir les dépassements de dépenses à travers des milliers de nœuds en périphérie, et la détection de fraude doit se faire en ligne sans ajouter des sauts réseau. Cette question est née de la nécessité de remplacer les pipelines centralisés Apache Kafka par des architectures de calcul en périphérie capables de prendre des décisions financières autonomes tout en maintenant des exigences strictes d'auditabilité et de résidence des données.

Le problème

Les architectures traditionnelles s'appuient sur des clusters centralisés PostgreSQL ou Redis pour les compteurs de budget et les magasins de fonctionnalités, créant une latence interrégionale qui viole le SLA de 100 ms lors de pics de trafic comme le Black Friday. Le verrouillage optimiste naïf sur les diminutions de budget cause des hordes tonitruantes et des enchères perdues, tandis que la détection de fraude asynchrone permet aux bots d'épuiser les budgets de campagne avant que les déclencheurs de détection ne se produisent. De plus, la réconciliation de facturation entre les DSP (plateformes du côté de la demande) souffre de partitions réseau où les pixels d'impression s'activent mais les messages d'accusé de réception disparaissent, entraînant une fuite de revenus ou une facturation en double qui détruit la confiance des annonceurs.

La solution

Déployez des Proxy Envoy en tant que sidecars avec des filtres WebAssembly aux points de présence (PoP) en périphérie pour exécuter la logique d'enchères en moins de 10 ms des utilisateurs finaux. Implémentez des compteurs CRDT (Type de données répliquées sans conflit) à l'aide de Redis avec un protocole Gossip pour le rythme budgétaire, permettant aux nœuds de périphérie d'accepter les enchères localement tout en garantissant la cohérence budgétaire globale grâce à une convergence éventuelle. Intégrez des modèles TensorFlow Lite légers dans la couche de périphérie pour la détection en temps réel des bots utilisant des empreintes comportementales telles que des motifs de vitesse de souris et d'entropie de navigation. Utilisez Apache Pulsar avec Geo-Réplication et BookKeeper pour des journaux d'audit immuables, garantissant des sémantiques de traitement exactes grâce à des Producteurs Idempotents et des Fenêtres de Dé-duplication. Pour se conformer au RGPD, implémentez des vérifications de K-Anonymité et un routage de résidence des données via DNS Anycast avec sensibilisation au Client Subnet EDNS.

Situation vécue

Lors de l'événement Black Friday 2023, notre plateforme a connu une augmentation de trafic de 40x qui a saturé notre magasin de budget centralisé Redis dans us-east-1, provoquant un dépassement de 12 % des enchères et menaçant une perte de revenus potentielle de 2 millions de dollars. L'équipe d'ingénierie a été confrontée à une décision architecturale critique : maintenir une cohérence forte et accepter des violations de latence, ou prioriser la vitesse et risquer un dépassement budgétaire catastrophique.

Solution A : Cluster Redis avec Redlock

Nous avons envisagé d'implémenter des algorithmes Redlock à travers cinq nœuds maîtres Redis indépendants pour appliquer une stricte cohérence budgétaire. Cette approche garantirait théoriquement qu'aucune campagne ne dépasse son plafond quotidien en nécessitant un consensus majoritaire pour chaque diminution. Cependant, le temps de trajet entre les nœuds périphériques et le cluster Redis était en moyenne de 35 ms, et sous charge, la contention de verrou a causé 8 % des demandes à être réessayées plusieurs fois, dépassant notre SLA de 100 ms. Bien que cela garantisse une précision budgétaire parfaite, la latence inacceptable et la complexité opérationnelle l'ont rendue inadaptée à l'enchère en temps réel.

Solution B : Mise en cache locale en mémoire avec synchronisation asynchrone

Alternativement, nous avons évalué la possibilité permettant à chaque nœud périphérique de maintenir des compteurs de budget purement locaux qui se synchronisaient de manière asynchrone à un registre central toutes les 30 secondes. Cela a permis d'atteindre une latence d'enchère de moins de 5 ms et de gérer le pic de trafic sans dépendances externes. Malheureusement, lors de la montée en charge, plusieurs nœuds périphériques ont vendu plus de campagnes à forte valeur ajoutée pour un total de 800 000 $ avant que la synchronisation ne se produise, causant des problèmes de confiance chez les annonceurs et des pénalités contractuelles. La vitesse était optimale, mais le risque financier était catastrophique pour un système adjoint aux paiements.

Solution C : Architecture hybride CRDT avec rythme hiérarchique

Nous avons mis en œuvre une approche hybride utilisant des CRDTs de Delta-State dans Redis à trois niveaux : périphérique, régional et global. Les nœuds périphériques acceptent les enchères en utilisant des PN-Counters (compteurs positifs-négatifs) avec des seuils locaux conservateurs fixés à 95 % du budget global. Lorsque les budgets locaux s'épuisent, les nœuds interrogent des caches régionaux avec une cohérence de Read-Your-Writes. Le reste du buffer de 5 % est géré par le registre global utilisant des fusions CRDT lors de la synchronisation de gossip. Pour la fraude, nous avons déployé des modèles TinyML sur les nœuds périphériques entraînés pour détecter les motifs de bots sans appels réseau. Nous avons choisi cette solution parce qu'elle fournissait une précision budgétaire de 99,9 % tout en maintenant une latence p99 de 45 ms.

Résultat

La plateforme a traité 12 millions de requêtes par seconde pendant le pic sans dépassement budgétaire sur les campagnes plafonnées. La latence de détection de fraude est tombée de 150 ms à 8 ms, bloquant 3,4 % du trafic malveillant avant la soumission des enchères. La réconciliation CRDT a atteint une cohérence éventuelle dans les 200 ms à travers les régions, bien dans la fenêtre de réconciliation de facturation, et la conformité au RGPD a été maintenue grâce au traitement local des données.

Ce que les candidats oublient souvent

Comment évitez-vous les dépassements de budget lorsque plusieurs nœuds périphériques décrémentent simultanément le même budget de campagne sans acquérir de verrous globaux ?

La plupart des candidats suggèrent des verrous distribués ou des opérations de décrémentation atomiques dans Redis, qui échouent en cas de partitions réseau ou de latence élevée. L'approche correcte utilise des PN-Counters (compteurs positifs-négatifs) mis en œuvre sous forme de CRDTs. Chaque nœud périphérique maintient un compteur d'incrémentation local pour les dépenses et un compteur de décrémentation pour les remboursements. Lorsqu'un nœud accepte une enchère, il incrémente son compteur de dépenses local. Lors de la synchronisation de gossip, les nœuds échangent leurs états de compteur et les fusionnent à l'aide de l'opération Join (prenant le maximum de chaque composant de compteur). Pour éviter un dépassement temporaire, implémentez des algorithmes de Seau de Jetons localement avec des plafonds conservateurs. Si la somme de toutes les dépenses locales approche la limite globale, les nœuds entrent dans un "mode d'économie" où ils interrogent le coordinateur régional pour les 5 % restants du budget. Cela garantit qu'alors qu'un dépassement temporaire de 1-2 % est théoriquement possible pendant la partition, le système ne dépasse jamais 105 % du budget, ce qui est acceptable pour les SLA de publicité numérique, contrairement aux systèmes bancaires traditionnels.

Comment garantissez-vous une facturation exacte lorsque les pixels de suivi des impressions s'activent à partir des navigateurs des utilisateurs mais que des pannes réseau empêchent la livraison d'accusés de réception au serveur d'enchères ?

Les candidats proposent souvent l'idempotence de Kafka ou des mises à jour de base de données, manquant ainsi le problème de bout en bout. La solution nécessite des Clés Idempotentes générées en périphérie à l'aide de UUIDv7 (ordonnées par temps) intégrées dans le code créatif. Lorsque le navigateur active le pixel d'impression, il inclut cette clé. La couche Nginx en périphérie écrit dans Apache Pulsar avec Dé-duplication Activée sur une fenêtre de 24 heures. Le stockage BookKeeper de Pulsar garantit que les écritures en double avec la même clé sont rejetées au niveau du courtier, et non au niveau du consommateur. De plus, implémentez une livraison Au Moins Une Fois vers une table de staging BigQuery partitionnée par la clé idempotente, avec des instructions MERGE qui dé-duplication lors du processus ETL. Cette protection à deux niveaux garantit que même si le navigateur réessaie le déclenchement du pixel 50 fois en raison d'erreurs 500, l'annonceur est facturé exactement une fois.

Comment gérez-vous le décalage horaire entre les enchérisseurs géographiquement distribués lors de la détermination des vainqueurs d'enchères en fonction du temps de réponse ?

Ceci est subtil. Les candidats suggèrent souvent NTP ou TrueTime (de Spanner), mais cela ajoute de la latence. L'architecture correcte élimine les dépendances sur l'heure murale de la logique d'enchères. Au lieu de comparer les horodatages des réponses DSP, utilisez des Horloges Logiques (horodatages de Lamport) ou simplement des files d'attente FIFO à la périphérie. Lorsque l'enchère commence, le nœud périphérique démarre un Minuteur Haute Résolution (Performance.now() dans V8 ou C++ chrono). Les réponses DSP sont classées par ordre d'arrivée à l'interface réseau, et non par en-têtes d'horodatage. Pour gérer les traînards, implémentez un Délai Réglable en utilisant des Algorithmes de Délai Adaptatifs qui s'ajustent en fonction de la latence p99 historique par DSP. Pour l'analyse post-hoc et les litiges de facturation, enregistrez la lecture de l'Horloge Monotone et l'Horodatage UTC avec des intervalles d'incertitude, les stockant dans CockroachDB qui gère automatiquement les fenêtres d'incertitude. Cela garantit l'équité même lorsque l'horloge d'un serveur DSP est en avance de 200 ms sur celle d'un autre.