Bonnes pratiques pour les applications RTB

Ce guide décrit les bonnes pratiques à prendre en compte lors du développement d'applications selon le protocole d'enchères en temps réel.

Gérer les connexions

Entretenez les connexions

L'établissement d'une nouvelle connexion augmente les latences et nécessite beaucoup plus de ressources aux deux extrémités que de réutiliser une connexion existante. En fermant moins de connexions, vous pouvez réduire le nombre de connexions à rouvrir.

Tout d'abord, chaque nouvelle connexion nécessite un aller-retour supplémentaire sur le réseau à établir. Étant donné que nous établissons des connexions à la demande, la première requête effectuée sur une connexion a un délai effectif plus court et a plus de chances d'expirer que les requêtes suivantes. Tout délai d'inactivité supplémentaire augmente le taux d'erreur, ce qui peut entraîner une limitation de votre système d'enchères.

Ensuite, de nombreux serveurs Web génèrent un thread de travail dédié pour chaque connexion établie. Cela signifie que pour fermer et recréer la connexion, le serveur doit arrêter et supprimer un thread, en attribuer un nouveau, le rendre exécutable et créer l'état de connexion, avant de traiter la requête. Cela représente beaucoup de frais généraux inutiles.

Éviter de fermer les connexions

Commencez par régler le comportement de la connexion. La plupart des serveurs par défaut sont adaptés aux environnements comportant un grand nombre de clients, chacun effectuant un petit nombre de requêtes. Pour les enchères en temps réel, en revanche, un petit pool de machines envoie des requêtes pour le compte d'un grand nombre de navigateurs. Dans ces conditions, il est judicieux de réutiliser les connexions autant de fois que possible. Nous vous recommandons de définir:

  • Délai d'inactivité à 2,5 minutes.
  • Nombre maximal de requêtes sur une connexion à la valeur la plus élevée possible.
  • Nombre maximal de connexions correspondant à la valeur la plus élevée que votre RAM peut accepter, tout en vérifiant que le nombre de connexions n'approche pas trop de cette valeur.

Dans Apache, par exemple, cela impliquerait de définir KeepAliveTimeout sur 150, MaxKeepAliveRequests sur zéro et MaxClients sur une valeur qui dépend du type de serveur.

Une fois le comportement de votre connexion ajusté, assurez-vous également que votre code d'enchérisseur ne ferme pas les connexions inutilement. Par exemple, si vous disposez d'un code frontal qui renvoie une réponse "aucune enchère" par défaut en cas d'erreurs de backend ou d'expiration du délai, assurez-vous que le code renvoie sa réponse sans fermer la connexion. Vous éviterez ainsi que, si votre système d'enchères est surchargé, que les connexions commencent à se fermer et que le nombre de délais avant expiration augmente, ce qui risque d'entraîner une limitation de votre système d'enchères.

Maintenir l'équilibre des connexions

Si Authorized Buyers se connecte aux serveurs de votre enchérisseur via un serveur proxy, les connexions peuvent être déséquilibrées avec le temps. En effet, ne connaissant que l'adresse IP du serveur proxy, Authorized Buyers ne peut pas déterminer quel serveur d'enchérisseur reçoit chaque appel. Au fil du temps, à mesure qu'Authorized Buyers établit et ferme des connexions, et que les serveurs de l'enchérisseur redémarre, le nombre de connexions mappées à chacune d'elles peut devenir très variable.

Lorsque certaines connexions sont utilisées de manière intensive, d'autres peuvent rester principalement inactives, car elles ne sont pas nécessaires à ce moment-là. À mesure que le trafic d'Authorized Buyers évolue, les connexions inactives peuvent devenir actives et les connexions actives peuvent devenir inactives. Cela peut entraîner des charges inégales sur vos serveurs d'enchères si les connexions sont mal regroupées. Google tente d'éviter ce problème en fermant toutes les connexions après 10 000 requêtes afin de rééquilibrer automatiquement les connexions à chaud au fil du temps. Si vous constatez toujours que le trafic est toujours déséquilibré dans votre environnement, vous pouvez prendre d'autres mesures:

  1. Si vous utilisez des proxys d'interface, sélectionnez le backend par requête plutôt qu'une fois par connexion.
  2. Spécifiez un nombre maximal de requêtes par connexion si vous faites passer des connexions par proxy via un équilibreur de charge matériel ou un pare-feu, et que le mappage est fixe une fois les connexions établies. Notez que Google spécifie déjà une limite supérieure à 10 000 requêtes par connexion. Vous ne devez donc fournir une valeur plus stricte que si vous constatez que des connexions à chaud sont toujours en cluster dans votre environnement. Dans Apache, par exemple, définissez MaxKeepAliveRequests sur 5 000
  3. Configurez les serveurs de l'enchérisseur de sorte qu'ils surveillent leurs taux de demandes et ferment certaines de leurs propres connexions s'ils traitent systématiquement trop de requêtes par rapport à leurs pairs.

Gestion optimale des surcharges

Idéalement, les quotas devraient être suffisamment élevés pour que votre enchérisseur puisse recevoir toutes les demandes qu'il est en mesure de traiter, mais pas plus que cela. En pratique, maintenir les quotas à des niveaux optimaux est une tâche difficile, et des surcharges peuvent se produire pour diverses raisons: un backend en panne pendant les heures de pointe, un mélange de trafic qui change de sorte qu'un traitement plus important est nécessaire pour chaque requête, ou une valeur de quota définie trop élevée. Vous avez donc intérêt à réfléchir au comportement de votre enchérisseur si le trafic entrant est trop important.

Pour tenir compte des changements de trafic temporaires (jusqu'à une semaine) entre les régions (en particulier entre l'Asie et l'Ouest des États-Unis, et l'Est et l'Ouest des États-Unis), nous recommandons une marge de 15% entre le pic sur sept jours et le RPS par zone d'échange.

En termes de comportement en cas de charges importantes, les enchérisseurs se répartissent en trois grandes catégories:

L'enchérisseur qui "répond à tout"

Bien qu'il soit facile à implémenter, cet enchérisseur est le moins performant lorsqu'il est surchargé. Il essaie simplement de répondre à toutes les demandes d'enchères reçues, quoi qu'il en soit, en mettant en file d'attente celles qui ne peuvent pas être diffusées immédiatement. Le scénario qui s'ensuit ressemble souvent à ceci:

  • La latence des requêtes augmente au fur et à mesure que le taux de demandes augmente, jusqu'à ce que toutes les requêtes commencent à expirer.
  • Les latences augmentent brusquement à mesure que les taux d'appels atteignent leur pic
  • La limitation s'active, ce qui réduit brusquement le nombre d'appels autorisés.
  • Les latences commencent à récupérer, ce qui réduit la limitation
  • Le cycle reprend.

Le graphique représentant la latence de ce système d'enchères ressemble à un schéma en dents de scie très abrupt. De même, les requêtes en file d'attente entraînent le démarrage de la pagination de la mémoire ou une autre action du serveur, ce qui entraîne un ralentissement à long terme. Les latences ne sont pas récupérées du tout jusqu'à la fin des pics d'activité, ce qui entraîne une baisse des taux d'appels pendant toute la période de pic d'activité. Dans les deux cas, le nombre d'appels reçus ou de réponses est moins élevé que si le quota avait simplement été défini sur une valeur inférieure.

Le système d'enchères qui renvoie une erreur en cas de surcharge

Ce type d'enchérisseur accepte les appels jusqu'à un certain taux, puis commence à renvoyer des erreurs pour certains d'entre eux. Pour ce faire, vous pouvez utiliser des délais d'inactivité internes, la désactivation de la mise en file d'attente des connexions (contrôlée par ListenBackLog sur Apache), l'implémentation d'un mode de suppression probabiliste lorsque l'utilisation ou les latences deviennent trop élevées, ou un autre mécanisme. Si Google constate un taux d'erreur supérieur à 15%, nous commençons à ralentir. Contrairement à l'enchérisseur qui "répond à tout", il "réduise les pertes", ce qui lui permet de récupérer immédiatement les données lorsque les taux de demandes diminuent.

Le graphique de latence de ce système d'enchères ressemble à un modèle en dents de scie superficielle en cas de surcharge, localisée autour du taux maximal acceptable.

Enchérisseur qui n'offre aucune enchère en cas de surcharge

Ce type d'enchérisseur accepte les appels jusqu'à un certain taux, puis commence à renvoyer des réponses "aucune enchère" en cas de surcharge. Tout comme pour le système d'enchères qui génère une erreur en cas de surcharge, il peut être implémenté de différentes manières. Ce qui est différent ici, c'est qu'aucun signal n'est renvoyé à Google. Nous ne limitons donc jamais les appels. La surcharge est absorbée par les machines frontend, ce qui permet seulement au trafic qu'elles peuvent gérer de passer par les backends.

Le graphique de latence pour ce système d'enchères montre un plateau qui cesse (artificiellement) le taux de demandes lors des pics d'activité, et une baisse correspondante de la fraction des réponses contenant une enchère.

Nous vous recommandons d'associer l'approche "erreur en cas de surcharge" à l'approche "aucune enchère en cas de surcharge", comme suit:

  • Surprovisionner les frontaux et les configurer en cas d'erreur en cas de surcharge, afin d'optimiser le nombre de connexions auxquelles ils peuvent répondre d'une manière ou d'une autre.
  • En cas d'erreur en cas de surcharge, les machines frontaux peuvent utiliser une réponse "no bid" standardisée et n'ont pas besoin d'analyser la demande.
  • Mettez en place des vérifications de l'état des backends, de sorte que, si aucun d'entre eux ne dispose d'une capacité suffisante, ils renvoient une réponse "no bid".

Cela permet d'absorber une partie de la surcharge et donne aux backends l'opportunité de répondre à autant de requêtes qu'ils peuvent en gérer. Vous pouvez considérer cela comme une "aucune enchère en cas de surcharge", et les machines frontaux recourent à une "erreur en cas de surcharge" lorsque le nombre de requêtes est considérablement plus élevé que prévu.

Si vous avez un enchérisseur qui répond à toutes les demandes, envisagez de le transformer en enchérisseur de type "erreur en cas de surcharge" en ajustant le comportement de la connexion de sorte qu'elle refuse d'être surchargée. Bien que cela entraîne le renvoi d'un plus grand nombre d'erreurs, cela réduit les délais avant expiration et empêche le serveur de se retrouver dans un état où il ne peut pas répondre à des requêtes.

Répondre aux pings

Il est étonnamment important de vous assurer que votre enchérisseur peut répondre aux demandes ping, même si vous ne gérez pas les connexions en soi, mais aussi pour le débogage. Google utilise les requêtes ping pour évaluer l'intégrité et déboguer l'état du système d'enchères, le comportement de fermeture de connexion, la latence, etc. Les demandes Ping se présentent sous la forme suivante:

Google

id: "\3503cg\3023P\364\230\240\270\020\255\002\231\314\010\362\347\351\246\357("
is_test: true
is_ping: true

JSON OpenRTB

"id": "4YB27BCXimH5g7wB39nd3t"

Protobuf OpenRTB

id: "7xd2P2M7K32d7F7Y50p631"

Gardez à l'esprit que, contrairement à ce à quoi vous pourriez vous attendre, la requête ping ne contient aucun espace publicitaire. Comme indiqué ci-dessus, ne fermez pas la connexion après avoir répondu à une requête ping.

Envisager l'appairage

Un autre moyen de réduire la latence ou la variabilité du réseau consiste à s'appairer à Google. L'appairage permet d'optimiser le chemin emprunté par le trafic pour accéder à votre enchérisseur. Les points de terminaison de la connexion restent les mêmes, mais les liaisons intermédiaires changent. Pour en savoir plus, consultez le guide d'appairage. La raison de considérer l'appairage comme une bonne pratique peut être résumée comme suit:

  • Sur Internet, les liens de transit sont principalement choisis via le "routage en mode "patate chaude", qui trouve le lien le plus proche en dehors de notre réseau pouvant recevoir un paquet vers sa destination et l'achemine via ce lien. Lorsque le trafic traverse une section d'un réseau backbone appartenant à un fournisseur avec lequel nous disposons de nombreuses connexions d'appairage, le lien choisi est susceptible d'être proche du point de départ du paquet. Au-delà, nous n'avons aucun contrôle sur l'itinéraire que le paquet suit jusqu'à l'enchérisseur. Il est donc susceptible d'être renvoyé vers d'autres systèmes autonomes (réseaux) en cours de route.

  • En revanche, lorsqu'un accord d'appairage direct est en place, les paquets sont toujours envoyés via une liaison d'appairage. Quelle que soit l'origine du paquet, il traverse les liens détenus ou loués par Google jusqu'à ce qu'il atteigne le point d'appairage partagé, qui doit se trouver à proximité de l'emplacement du système d'enchères. Le trajet inverse commence par un court saut sur le réseau Google et reste sur le réseau Google pour le reste du trajet. Le fait de garder la majeure partie du trajet sur une infrastructure gérée par Google garantit que le paquet suit une route à faible latence, ce qui évite une grande variabilité potentielle.

Envoyer un DNS statique

Nous recommandons aux acheteurs de toujours envoyer un seul résultat DNS statique à Google et de compter sur Google pour gérer la diffusion du trafic.

Voici deux pratiques courantes utilisées par les serveurs DNS des enchérisseurs lorsqu'ils tentent d'équilibrer la charge ou de gérer la disponibilité:

  1. Le serveur DNS distribue une adresse ou un sous-ensemble d'adresses en réponse à une requête, puis fait défiler cette réponse d'une manière ou d'une autre.
  2. Le serveur DNS répond toujours avec le même ensemble d'adresses, mais recycle l'ordre des adresses dans la réponse.

La première technique n'est pas adaptée à l'équilibrage de charge, car la mise en cache est importante à plusieurs niveaux de la pile. Les tentatives de contournement de la mise en cache n'obtiendront probablement pas les résultats préférés de même que Google facture le temps de résolution DNS à l'enchérisseur.

La deuxième technique ne permet pas d'équilibrer la charge du tout, car Google sélectionne de manière aléatoire une adresse IP dans la liste de réponses DNS. L'ordre dans la réponse n'a donc pas d'importance.

Si un enchérisseur modifie le DNS, Google respecte la valeur TTL(Time To Live) définie dans ses enregistrements DNS, mais l'intervalle d'actualisation reste incertain.