Il y a bientôt de trois ans de cela, nous avons inauguré Cloudflare Waiting Room dans le but de protéger les sites de nos clients contre les pics de trafic légitime susceptibles d'entraîner leur arrêt. Waiting Room permet aux clients de contrôler l'expérience des utilisateurs, même en présence d'un trafic important, en transférant l'excédent de trafic vers une « salle d'attente » personnalisable, conforme à l'image de marque des entreprises, qui assure l'admission dynamique des utilisateurs sur les sites web au fur et à mesure que des places se libèrent. Depuis le lancement de Waiting Room, nous avons continué à développer les fonctionnalités du service en nous inspirant des commentaires de nos clients, en déployant des fonctions telles que la prise en charge d'applications mobiles, l'analyse de données, les règles de contournement de Waiting Room et d'autres encore.
Nous aimons annoncer de nouvelles fonctionnalités et résoudre les problèmes de nos clients en étendant les capacités de Waiting Room,mais aujourd'hui, nous vous invitons à découvrir les coulisses du développement du mécanisme fondamental de notre produit, à savoir la manière dont il agit pour mettre le trafic en file d'attente en réponse aux pics d'affluence.
Comment Waiting Room a-t-il été développé, et quels sont les défis à relever ?
Le diagramme ci-dessous fournit un aperçu rapide de l'endroit où est déployé Waiting Room lorsqu'un client l'active pour son site web.
Vue d'ensemble de Waiting Room
Waiting Room est développé avec Workers, qui s'exécute sur un réseau mondial de datacenters de Cloudflare. Les requêtes adressées au site web d'un client peuvent être acheminées vers de nombreux datacenters Cloudflare différents. Pour optimiser l'acheminement dans le but de minimiser la latence et d'améliorer les performances, ces requêtes sont acheminées vers le datacenter le plus proche géographiquement. Lorsqu'un nouvel utilisateur adresse une requête à l'hôte/au chemin couvert par la solution Waiting Room, l'instance Workers associée à la « salle d'attente » décide s'il est nécessaire de rediriger l'utilisateur vers le serveur d'origine ou cette salle d'attente. Cette décision est prise en fonction de l'état de la salle d'attente, qui donne une idée du nombre d'utilisateurs présents sur le serveur d'origine.
L'état de la salle d'attente évolue continuellement, en fonction de la situation du trafic dans le monde entier. Ces informations peuvent être stockées dans un emplacement central, ou des modifications peuvent être progressivement propagées à travers le monde. Le stockage de ces informations dans un emplacement central peut ajouter une latence considérable à chaque requête, car l'emplacement central peut être très éloigné de l'endroit d'où provient la requête. Par conséquent, chaque datacenter opère en fonction de l'état de la salle d'attente qui lui est propre ; il s'agit d'un instantané, disponible à cet instant, de la répartition du trafic correspondant à ce site web dans le monde entier. Nous ne voulons pas être contraints d'attendre la réception d'informations provenant de partout ailleurs dans le monde avant d'autoriser un utilisateur à accéder au site web, car cette attente ajouterait une latence considérable à la requête. C'est la raison pour laquelle nous avons choisi de ne pas déployer un emplacement central, mais un pipeline dans lequel les fluctuations du trafic se propagent éventuellement dans le monde entier.
Ce pipeline, qui agrège l'état de la salle d'attente en arrière-plan, est développé avec Cloudflare Durable Objects. En 2021, nous avons publié un article de blog expliquant le fonctionnement du pipeline d'agrégation, ainsi que les différentes décisions que nous avons prises durant sa conception, si cela vous intéresse. Ce pipeline garantit que chaque datacenter reçoit des informations actualisées sur les fluctuations du trafic en l'espace de quelques secondes seulement.
Waiting Room doit prendre la décision de rediriger les utilisateurs vers le site web ou de les placer dans la file d'attente, en fonction de l'état qu'elle observe actuellement. Pour prendre cette décision, nous devons nous assurer que la mise en file d'attente soit effectuée au moment opportun, afin que le site web du client ne soit pas surchargé. Nous devons également veiller à ne pas trop anticiper la mise en file d'attente, au risque de mettre en file d'attente des utilisateurs pendant un pic de trafic identifié par erreur. En effet, le fait d'être placés dans une file d'attente peut inciter certains utilisateurs à renoncer à accéder au site web. Waiting Room s'exécute sur tous les serveurs formant le réseau de Cloudflare, présent dans plus de 300 villes dans plus de 100 pays. Pour chaque nouvel utilisateur, nous voulons nous assurer de prendre la décision de rediriger l'utilisateur vers le site web ou le placer dans la file d'attente avec une latence minimale. C'est cet aspect qui rend complexe, pour Waiting Room, la décision de mettre un utilisateur en file d'attente. Dans cet article de blog, nous expliquons comment nous avons abordé ce compromis. Notre algorithme a évolué, afin de réduire le taux de faux positifs, tout en continuant à respecter les limites établies par le client.
Comment Waiting Room décide de la mise en file d'attente des utilisateurs
Le facteur le plus important pour déterminer l'instant auquel Waiting Room commencera à placer des utilisateurs dans une file d'attente est la configuration des paramètres de trafic. Deux limites de trafic sont définies lors de la configuration d'une salle d'attente : le nombre total d'utilisateurs actifs et le nombre de nouveaux utilisateurs par minute. Le nombre total d'utilisateurs actifs est un seuil cible correspondant au nombre d'utilisateurs simultanés que vous souhaitez autoriser à accéder aux pages couvertes par Waiting Room. Le nombre de nouveaux utilisateurs par minute définit le seuil cible pour le taux maximal d'afflux d'utilisateurs par minute sur votre site web. Une forte soudaine de l'une ou l'autre de ces valeurs peut entraîner la mise en d'attente d'utilisateurs. Une autre configuration qui affecte la façon dont nous calculons le nombre total d'utilisateurs actifs est la durée de la session. Un utilisateur est considéré comme actif pendant un nombre de minutes correspondant à la durée de la session, puisque la requête est adressée à n'importe quelle page couverte par Waiting Room.
Le graphique ci-dessous est extrait de l'un de nos outils de surveillance interne pour un client et représente la structure du trafic d'un client sur une période de 2 jours. Ce client a défini ses limites, le nombre de nouveaux utilisateurs par minute et le nombre total d'utilisateurs actifs, à 200 et 200, respectivement.
Trafic du client pendant 2 jours entre le 9 et le 11 septembre, avec 2 pics de trafic
Si vous regardez le trafic de l'entreprise, vous pouvez voir que des utilisateurs ont été mis en file d'attente le 11 septembre, vers 11h45. À cette heure, le nombre total d'utilisateurs actifs était d'environ 200. Lorsque le nombre total d'utilisateurs actifs a diminué, vers 12h30, le nombre d'utilisateurs dans la file d'attente a atteint 0. La mise en file d'attente a recommencé le 11 septembre, vers 15h00, lorsque le nombre total d'utilisateurs actifs a atteint 200. La mise en file d'attente d'utilisateurs à ce moment a permis d'assurer que le trafic affluant vers le site web était conforme aux limites définies par le client.
{
"bucketId": "Mon, 11 Sep 2023 11:45:00 GMT",
"lastCheckInTime": "Mon, 11 Sep 2023 11:45:54 GMT",
"acceptedAt": "Mon, 11 Sep 2023 11:45:54 GMT"
}
Lorsqu'un utilisateur accède au site web, nous lui transmettons un cookie chiffré indiquant qu'il a déjà obtenu l'accès. Le contenu du cookie peut se présenter comme ceci.
Le cookie s'apparente à un « ticket » indiquant l'entrée de l'utilisateur dans la salle d'attente. Le champ bucketId indique à quel groupe d'utilisateurs cet utilisateur appartient. Les champs acceptedAt et lastCheckInTime indiquent la date de la dernière interaction avec Workers. Ces informations permettent de vérifier si le ticket est ou non valable pour l'accès lorsque nous le comparons à la valeur de durée de la session définie par le client lors de la configuration de Waiting Room. Si le cookie est valide, nous acceptons l'utilisateur, ce qui garantit que les utilisateurs présents sur le site web continuent à pouvoir parcourir le site. Si le cookie n'est pas valide, nous créons un nouveau cookie qui traite l'utilisateur comme un nouvel utilisateur et, si une file d'attente est active sur le site web, l'utilisateur est transféré vers la fin de la file d'attente. Dans la section suivante, nous allons voir comment nous décidons quand transférer ces utilisateurs vers la file d'attente.
{
"activeUsers": 50,
}
Pour mieux comprendre, examinons le contenu de l'état de la salle d'attente. Pour le client dont nous avons parlé plus haut, à l'heure "Mon, 11 Sep 2023 11:45:54 GMT", l'état pourrait se présenter ainsi :
Comme indiqué ci-dessus, le client a configuré des valeurs de nouveaux utilisateurs par minute et de nombre total d'utilisateurs actifs égales à 200 et 200, respectivement.
{
"activeUsers": 50,
"globalWorkersActive": 10,
"dataCenterWorkersActive": 3,
"trafficHistory": {
"Mon, 11 Sep 2023 11:44:00 GMT": {
San Jose: 20/200, // 10%
London: 30/200, // 15%
Anywhere: 150/200 // 75%
}
}
}
L'état indique donc qu'il y a de la place pour les nouveaux utilisateurs, puisque seulement 50 utilisateurs actifs sont présents, alors qu'ils peuvent être au nombre de 200. Il y a donc de la place pour 150 utilisateurs supplémentaires. Supposons que ces 50 utilisateurs proviennent de deux datacenters : San Jose (20 utilisateurs) et Londres (30 utilisateurs). Nous surveillons également le nombre d'instances Workers actives dans le monde entier, ainsi que le nombre d'instances Workers actives dans le datacenter dans lequel est calculé l'état. La clé d'état ci-dessous pourrait être celle calculée à San Jose.
Imaginons qu'à l'heure "Mon, 11 Sep 2023 11:45:54 GMT
", nous recevons une requête pour rejoindre la salle d'attente d'un datacenter à San Jose.
Pour déterminer si l'utilisateur ayant atteint San Jose peut être redirigé vers le serveur d'origine, nous examinons d'abord l'historique du trafic durant la dernière minute, afin de consulter la répartition du trafic à cette heure. En effet, de nombreux sites web sont populaires dans certaines régions du monde,et pour un grand nombre de ces sites web, le trafic tend à provenir des mêmes datacenters.
Si nous examinons l'historique du trafic pour la minute "Mon, 11 Sep 2023 11:44:00 GMT
", nous voyons qu'à San Jose, 20 utilisateurs sur 200 (soit 10 %) accèdent au site web à cette heure. Pour l'heure actuelle, "Mon, 11 Sep 2023 11:45:54 GMT
", nous répartissons les emplacements disponibles sur le site web conformément au ratio de l'historique du trafic durant la dernière minute. Nous pouvons donc rediriger 10 % des 150 créneaux disponibles vers San Jose, soit 15 utilisateurs. Nous savons également que trois instances Workers sont actives, car le champ "dataCenterWorkersActive
" indique 3
.
Le nombre d'emplacements disponibles pour le datacenter est divisé de manière égale entre les instances Workers du datacenter. Ainsi, chaque instance Workers de San Jose peut rediriger 15/3, c'est-à-dire cinq utilisateurs vers le site web. Si l'instance Workers qui a reçu le trafic n'a pas redirigé d'utilisateurs vers le serveur d'origine pendant la minute en cours, il peut rediriger jusqu'à cinq utilisateurs (15/3).
{
"activeUsers":50,
"globalWorkersActive": 10,
"dataCenterWorkersActive": 1,
"trafficHistory": {
"Mon, 11 Sep 2023 11:44:00 GMT": {
San Jose: 20/200, // 10%
London: 30/200, // 15%
Anywhere: 150/200 // 75%
}
}
}
À la même heure ("Mon, 11 Sep 2023 11:45:54 GMT
"), imaginons qu'une requête soit adressée à un datacenter situé à Delhi. L'instance Workers du datacenter de Delhi vérifie l'historique du trafic et constate qu'aucun emplacement n'est alloué à cette requête. Pour ce type de trafic, nous avons réservé les emplacements Anywhere, car nous sommes très loin de la limite définie.
Les emplacements Anywhere
sont répartis entre toutes les instances Workers actives dans le monde, car n'importe quelle instance Workers dans le monde peut s'accaparer « une part de ce gâteau ». 75 % des 150 emplacements restants égale 113.
La clé d'état assure également le suivi du nombre d'instances Workers (globalWorkersActive
) créées dans le monde. Les emplacements Anywhere attribués sont répartis entre toutes les instances Workers actives dans le monde, s'ils sont disponibles. Lorsque nous examinons l'état de la salle d'attente, le champ globalWorkersActive indique 10. Chaque instance Workers active peut donc rediriger jusqu'à 113/10 utilisateurs, soit environ 11 utilisateurs. Ainsi, les 11 premiers utilisateurs qui se présentent à une instance Workers dans la minute "Mon, 11 Sep 2023 11:45:00 GMT
" sont autorisés à accéder au serveur d'origine. Les utilisateurs supplémentaires sont mis en file d'attente. Les emplacements réservés supplémentaires (5) dans le datacenter de San Jose pour la minute "Mon, 11 Sep 2023 11:45:00 GMT
" précédemment évoquée nous assurent de pouvoir autoriser jusqu'à (5+11) utilisateurs, soit seize utilisateurs provenant d'une instance Workers à San Jose à accéder au site web.
La mise en file d'attente au niveau de l'instance Workers peut entraîner la mise en file d'attente d'utilisateurs avant que les emplacements disponibles pour le datacenter ne soient remplis.
Comme le montre l'exemple ci-dessus, c'est au niveau de l'instance Workers qu'a lieu la décision de transférer ou non un utilisateur vers la file d'attente. Le nombre de nouveaux utilisateurs qui se présentent à une instance Workers dans le monde entier peut ne pas être uniforme. Pour comprendre ce qui peut se passer en cas de répartition non uniforme du trafic entre deux instances Workers, examinons le diagramme ci-dessous.
Effet secondaire de la répartition des emplacements au niveau des instances Workers
Imaginons que le nombre d'emplacements disponibles pour un datacenter à San Jose soit de dix. Deux instances Workers sont en cours d'exécution à San Jose. Sept utilisateurs sont acheminés à l'instance worker1 et un utilisateur à l'instance worker2. Dans cette situation, l'instance worker1 autorise cinq des sept utilisateurs à accéder au site web, et autorise deux d'entre eux à rejoindre la file d'attente, car l'instance worker1 ne compte que cinq emplacements disponibles. L'utilisateur unique qui se présente à l'instance worker2 accède également au serveur d'origine. Par conséquent, deux utilisateurs sont mis en file d'attente, alors qu'en réalité, dix utilisateurs peuvent être redirigés depuis le datacenter de San Jose, alors que seulement huit utilisateurs se sont présentés.
Ce problème, qui affecte la répartition homogène des emplacements entre les instances Workers, entraîne des mises en files d'attente avant que les limites de trafic configurées dans Waiting Room ne soient atteintes, généralement dans une fourchette de 20 à 30 % des limites définies. Cette approche présente des avantages que nous examinerons plus loin. Nous avons modifié notre approche afin de réduire la fréquence à laquelle la mise en file d'attente survient en dehors de cette fourchette de 20 à 30 %, en nous rapprochant autant que possible des limites, tout en veillant à ce que Waiting Room soit prêt à réagir à d'éventuels pics d'affluence. Plus loin dans cet article de blog, nous verrons comment nous y sommes parvenus en actualisant la façon dont nous allouons et comptons les emplacements.
Quel est l'avantage de confier ces décisions à Workers ?
L'exemple ci-dessus décrit comment des instances Workers à San Jose et Delhi prennent la décision d'autoriser des utilisateurs à accéder au serveur d'origine. L'avantage de la prise de décisions au niveau de l'instance Workers est que nous pouvons prendre des décisions sans ajouter une latence considérable à la requête. En effet, pour prendre la décision, il n'est pas nécessaire de quitter le datacenter pour obtenir des informations concernant la salle d'attente, car nous nous référons toujours à l'état actuellement disponible dans le datacenter. La mise en file d'attente commence lorsque l'instance Workers commence à manquer d'emplacements.L'absence de latence supplémentaire permet aux clients d'activer en permanence la salle d'attente, sans se préoccuper de la latence supplémentaire pour leurs utilisateurs.
La priorité absolue de Waiting Room est d'assurer que les sites des clients restent opérationnels à tout moment, même en cas d'augmentation inattendue et importante du trafic. À cette fin, il est essentiel que la priorité de Waiting Room soit que le nombre d'utilisateurs reste proche, voire en dessous des limites de trafic définies par le client pour une salle d'attente. Lorsqu'un pic d'affluence se produit dans un datacenter quelque part dans le monde (par exemple, à San Jose), l'état local du datacenter met quelques secondes à atteindre Delhi.
La répartition des emplacements entre les instances Workers permet d'assurer que l'utilisation de données légèrement obsolètes n'entraîne pas de dépassement problématique de la limite globale. Par exemple, la valeur activeUsers
peut être de 26 dans le datacenter de San Jose et de 100 dans l'autre datacenter, où se produit le pic d'affluence. À ce moment-là, la redirection d'utilisateurs supplémentaires depuis Delhi peut ne pas entraîner de dépassement considérable de la limite globale, puisque les utilisateurs ne disposent que « d'une part du gâteau » à l'origine, à Delhi. Par conséquent, la mise en file d'attente avant que les limites globales ne soient atteintes fait partie intégrante de la conception du service, et permet d'assurer le respect des limites globales. Dans la section suivante, nous examinerons les approches que nous avons mises en œuvre pour assurer la mise en file d'attente à un seuil aussi proche que possible des limites, sans toutefois augmenter le risque de dépassement des limites de trafic.
Attribuer un plus grand nombre d'emplacements lorsque le trafic est faible par rapport aux limites définies dans Waiting Room
Le premier scénario auquel nous voulions répondre était celui du déclenchement de la mise en file d'attente alors que le trafic est encore loin des limites définies. Bien que ce phénomène survienne rarement et qu'il ne dure généralement qu'un intervalle de rafraîchissement (c'est-à-dire 20 secondes) pour les utilisateurs finaux mis en file d'attente, il s'agissait de notre priorité absolue lors de la mise à jour de notre algorithme de mise en file d'attente. Pour remédier à ce problème, lors de l'allocation d'emplacements, nous avons examiné le taux d'utilisation (c'est-à-dire l'écart par rapport aux limites de trafic définies) et avons attribué un plus grand nombre d'emplacements lorsque le trafic est encore vraiment loin des limites. L'idée sous-jacente était d'éviter que la mise d'attente se produise à des limites inférieures, tout en conservant la capacité de réajuster le nombre d'emplacements disponibles par instance Workers lorsqu'un plus grand nombre d'utilisateurs étaient présents sur le serveur d'origine.
Pour comprendre cela, reprenons l'exemple d'une répartition non uniforme du trafic affluant vers deux instances Workers. À cette fin, deux instances Workers semblables à celle décrite plus haut sont présentées ci-dessous. Dans ce scénario, le taux d'utilisation est faible (10 %),ce qui signifie que nous sommes loin des limites définies. Le nombre d'emplacements alloués (8) est donc plus proche de la valeur slotsAvailable
pour le datacenter de San Jose, pour lequel la valeur est de 10. Comme indiqué sur le diagramme ci-dessous, avec cette nouvelle répartition des emplacements, les huit utilisateurs qui accèdent à l'une ou l'autre des instances Workers peuvent atteindre le site web, car nous fournissons un plus grand nombre d'emplacements par instance Workers à des taux d'utilisation inférieurs.
Répartition des emplacements entre les instances Workers à un taux d'utilisation moins élevé
Le diagramme ci-dessous indique comment le nombre d'emplacements alloués par instance Workers évolue en fonction du taux d'utilisation (c'est-à-dire de l'écart par rapport aux limites définies). Comme vous pouvez le voir ici, nous allouons un plus grand nombre d'emplacements par instance Workers à un taux d'utilisation moins élevé. À mesure l'utilisation augmente, le nombre d'emplacements alloués par instance Workers diminue, car la valeur se rapproche des limites et nous sommes mieux préparés à faire face aux pics de trafic. À un taux d'utilisation de 10 %, le nombre d'emplacements alloués à chaque instance Workers se rapproche du nombre d'emplacements disponibles pour le datacenter. Lorsque l'utilisation est proche de 100 %, elle se rapproche du nombre d'emplacements disponibles divisé par le nombre d'instances Workers dans le datacenter.
{
"activeUsers": 50,
"globalWorkersActive": 10,
"dataCenterWorkersActive": 1,
"trafficHistory": {
"Mon, 11 Sep 2023 11:44:00 GMT": {
San Jose: 20/200, // 10%
London: 30/200, // 15%
Anywhere: 150/200 // 75%
}
}
}
Allouer un plus grand nombre d'emplacements à des limites inférieures
Comment augmenter le nombre d'emplacements disponibles à un taux d'utilisation inférieur ?
workerMultiplier = (utilization)^curveFactor
adaptedWorkerCount = actualWorkerCount * workerMultiplier
Dans cette section, nous examinons les considérations mathématiques qui nous permettent d'y parvenir. Si ces détails ne vous intéressent pas, rendez-vous à la section « Risque de surprovisionnement .
Pour mieux comprendre cet aspect, reprenons l'exemple précédent, dans lequel les requêtes parviennent au datacenter de Delhi. La valeur activeUsers
étant de 50, l'utilisation est donc de 50/200, soit d'environ 25 %.
L'idée est d'allouer un plus grand nombre de créneaux à des taux d'utilisation moins élevés, ce qui permet d'assurer que les clients n'observent pas de comportements inattendus de mise en file d'attente lorsque le trafic est loin des limites définies. À l'heure "Mon, 11 Sep 2023 11:45:54 GMT
", les requêtes transmises à Delhi représentent un taux d'utilisation de 25 % sur la base de la clé d'état locale.
Pour allouer un plus grand nombre d'emplacements à un taux d'utilisation moindre, nous avons ajouté un champ workerMultiplier
, qui évolue proportionnellement à l'utilisation. À un taux d'utilisation faible, le multiplicateur est inférieur, et à un taux d'utilisation élevé, il est proche de un.
utilization
– l'écart par rapport aux limites définies.
curveFactor
– est l'exposant, qui peut être ajusté, et qui détermine le degré d'agressivité de la répartition des budgets supplémentaires lorsque le nombre d'instances Workers est moins élevé. Pour comprendre, examinons le graphique de la relation y = x et y = x^2 entre les valeurs 0 et 1.
Graphique y=x^curveFactor
Le graphique y=x est une droite passant par (0, 0) et (1, 1).
Le graphique y=x^2
est une courbe où y augmente moins vite que x
lorsque x < 1
, et qui passe par (0, 0) et (1, 1).
En appliquant le concept de fonctionnement des courbes, nous avons dérivé la formule workerCountMultiplier
où y=workerCountMultiplier
, x=utilization
et curveFactor
représente la puissance, qui peut être ajustée et décide de l'agressivité avec laquelle nous répartissons les budgets supplémentaires lorsque le nombre d'instances Workers est moins élevé. Lorsque curveFactor est égal à 1, la valeur workerMultiplier
est égale à l'utilisation.
Revenons à l'exemple précédent, et voyons quelle sera la valeur du facteur de courbe. À l'heure "Mon, 11 Sep 2023 11:45:54 GMT
", les requêtes transmises à Delhi représentent un taux d'utilisation de 25 % sur la base de la clé d'état locale. Les emplacements Anywhere sont répartis entre la totalité instances Workers actives dans le monde, puisque n'importe quelle instance Workers peut s'accaparer « une part de ce gâteau », c'est-à-dire 75 % des 150 emplacements restants (soit 113 emplacements).
La valeur globalWorkersActive
est de 10 lorsque nous examinons l'état de la salle d'attente. Dans ce cas, nous ne divisons pas les 113 emplacements par 10, mais divisons au lieu de cela le nombre ajusté d'instances Workers, qui est égal à globalWorkersActive ***** workerMultiplier
. Si la valeur curveFactor est égale à 1, la valeur workerMultiplier est égale au taux d'utilisation, qui est de 25 %, soit 0,25.
Ainsi, la valeur workerCount
effective est égale à 10 × 0,25 = 2,5.
Par conséquent, chaque instance Workers active peut rediriger jusqu'à 113/2,5, soit environ 45 utilisateurs. Les 45 premiers utilisateurs qui se présentent à une instance Workers dans la minute "Mon, 11 Sep 2023 11:45:00 GMT
" sont autorisés à accéder au serveur d'origine. Les utilisateurs supplémentaires sont mis en file d'attente.
Par conséquent, lorsque le taux d'utilisation est plus faible (c'est-à-dire lorsque le trafic est plus éloigné des limites définies), chaque instance Workers dispose d'un plus grand nombre d'emplacements. Toutefois, si l'on calcule la somme des emplacements, le risque de dépasser la limite globale est plus élevé.
Risque de surprovisionnement
La méthode consistant à allouer un plus grand nombre d'emplacements aux limites inférieures atténue les risques de mise en file d'attente lorsque le trafic est faible par rapport aux limites de trafic définies. Toutefois, à des taux d'utilisation inférieurs, un pic de trafic uniforme survenant dans le monde entier pourrait entraîner un nombre d'utilisateurs plus élevé que prévu sur le serveur d'origine. Le diagramme ci-dessous présente le scénario dans lequel cela pourrait poser problème. Comme vous pouvez le voir, les emplacements disponibles pour le datacenter sont au nombre de dix. Comme nous l'avons vu précédemment, à un taux d'utilisation de 10 %, chaque instance Workers peut disposer de huit emplacements. Si huit utilisateurs se présentent à une instance Workers et sept utilisateurs à une autre, nous redirigerons quinze utilisateurs vers le site web, alors que dix emplacements seulement sont disponibles au niveau du datacenter.
Risque de surprovisionnement à un taux d'utilisation faible
L'éventail de clients et de types de trafic que nous pouvons observer nous a permis d'identifier les scénarios dans lesquels cette situation devenait problématique. Un pic de trafic lié à un taux d'utilisation peu élevé peut entraîner un dépassement des limites globales. En effet, un surprovisionnement a lieu aux limites inférieures, augmentant le risque d'un dépassement important des limites de trafic. Nous devions mettre en œuvre une approche plus sûre, qui n'entraînerait pas de dépassement des limites, tout en réduisant les risques de mise en file d'attente lorsque le trafic est très peu élevé par rapport aux limites définies.
Nous avons donc pris du recul et avons réfléchi à notre approche, et nous sommes partis du principe que le trafic dans un datacenter est directement corrélé avec le nombre d'instances Workers qui y sont exécutées. Dans la pratique, toutefois, nous avons constaté que ce n'était pas le cas pour tous les clients. Même si le trafic est corrélé avec le nombre d'instances Workers, le nombre de nouveaux utilisateurs affluant vers les instances Workers dans les datacenters peut ne pas être corrélé avec le trafic. En effet, les emplacements que nous allouons sont destinés aux nouveaux utilisateurs ; cependant, le trafic affluant dans un datacenter est constitué à la fois d'utilisateurs déjà présents sur le site web et de nouveaux utilisateurs tentant d'y accéder.
Dans la section suivante, nous décrivons une approche selon laquelle le nombre d'instances Workers n'est pas pris en compte et, au lieu de cela, les instances Workers communiquent avec d'autres instances Workers dans le datacenter. Pour cela, nous avons inauguré un nouveau service, qui est un compteur Durable Objects.
Réduire le nombre de fois que nous répartissons les emplacements grâce à l'introduction des compteurs Data Center Counter
Dans l'exemple ci-dessus, nous pouvons voir que le surprovisionnement au niveau de l'instance Workers entraîne le risque d'utiliser un nombre d'emplacements supérieur au nombre alloué à un datacenter. Si nous n'effectuons pas de surprovisionnement à des niveaux peu élevés, nous courons le risque de mettre des utilisateurs en file d'attente bien avant que les limites configurées ne soient atteintes, comme nous l'avons vu précédemment. Il est donc nécessaire de trouver une solution qui tienne compte de ces deux contraintes.
Le surprovisionnement a été mis en œuvre afin d'éviter que des instances Workers ne manquent rapidement d'emplacements lorsqu'un nombre non uniforme de nouveaux utilisateurs parvient à un groupe de ces instances. S'il existe un moyen d'établir des communications entre deux instances Workers dans un datacenter, il n'est pas nécessaire de répartir les emplacements entre les instances Workers dans le datacenter en fonction du nombre d'instances Workers. Pour mettre ces communications en œuvre, nous avons introduit des compteurs. Ces compteurs sont un ensemble de petites instances Durable Objects qui assurent le comptage pour un ensemble d'instances Workers dans le datacenter.
Pour comprendre comment ces compteurs permettent d'éviter d'avoir recours au comptage des instances Workers, examinons le diagramme ci-dessous : deux instances Workers communiquent avec un compteur Data Center Counter. Comme nous l'avons vu précédemment, les instances Workers autorisent les utilisateurs à accéder au site web en fonction de l'état de la salle d'attente. Le comptage du nombre d'utilisateurs autorisés à accéder au site web était précédemment stocké dans la mémoire de l'instance Workers. L'introduction de compteurs permet de stocker cette information dans le compteur Data Center Counter. Chaque fois qu'un nouvel utilisateur transmet une requête à l'instance Workers, cette dernière communique avec le compteur, afin de connaître la valeur actuelle de celui-ci. Dans l'exemple ci-dessous, pour la première nouvelle requête adressée à l'instance Workers, la valeur du compteur reçue est de 9. Lorsqu'un datacenter dispose de 10 emplacements disponibles, l'utilisateur est autorisé à accéder au site web. Si l'instance Workers suivante reçoit un nouvel utilisateur et transmet une requête immédiatement après, elle obtient une valeur de 10 et, en fonction du nombre d'emplacements disponibles pour l'instance Workers, l'utilisateur sera transféré vers la file d'attente.
{
"activeUsers": 50,
"globalWorkersActive": 10,
"dataCenterWorkersActive": 3,
"trafficHistory": {
"Mon, 11 Sep 2023 11:44:00 GMT": {
San Jose: 20/200, // 10%
London: 30/200, // 15%
Anywhere: 150/200 // 75%
}
}
}
Les compteurs aident les instances Workers à communiquer entre elles
Le compteur Data Center Counter se comporte comme un point de synchronisation pour les instances Workers dans la salle d'attente. Il permet fondamentalement aux instances Workers de communiquer, sans toutefois communiquer directement entre elles. Son fonctionnement est similaire à celui d'un compteur de billetterie : chaque fois qu'une instance Workers admet un utilisateur, elle demande des tickets au compteur ; par conséquent, une autre instance Workers demandant des tickets au compteur ne recevra pas un ticket portant le même numéro. Si la valeur du ticket est valide, le nouvel utilisateur est autorisé à accéder au site web. Ainsi, lorsque différents nombres de nouveaux utilisateurs se présentent aux instances Workers, nous évitons d'allouer un nombre trop élevé ou insuffisant d'emplacements à l'instance Workers, car le nombre d'emplacements utilisés est calculé par le compteur correspondant au datacenter.
Le diagramme ci-dessous illustre le comportement qui se produit lorsqu'un nombre non uniforme de nouveaux utilisateurs atteint des instances Workers : une instance reçoit sept nouveaux utilisateurs, et l'autre en reçoit un. Les huit utilisateurs qui se présentent aux instances Workers dans le diagramme ci-dessous sont autorisés à accéder au site web, car le nombre d'emplacements disponibles pour le datacenter est de dix, soit une valeur supérieure à huit.
Un nombre non uniforme de requêtes parvenant aux instances Workers n'entraîne pas de mise en file d'attente
Cette approche n'entraîne pas non plus l'autorisation pour un nombre excessif d'utilisateurs d'accéder au site web, car aucun utilisateur supplémentaire n'est redirigé vers le site web lorsque la valeur du compteur est égale au nombre d'emplacements disponibles pour le datacenter. Sur les quinze utilisateurs qui se présentent aux instances Workers dans le diagramme ci-dessous, dix seront autorisés à accéder au site web, et cinq seront transférés vers la file d'attente, ce qui correspond aux valeurs attendues.
Le risque de surprovisionnement à un taux d'utilisation réduit n'existe pas non plus, car les compteurs aident les instances Workers à communiquer entre elles.
Pour mieux comprendre ce principe, reprenons l'exemple précédent et examinons de quelle manière il opère avec l'état réel de la salle d'attente.
L'état de la salle d'attente du client est le suivant :
L'objectif n'est pas de répartir les emplacements entre les instances Workers ; nous n'avons donc pas besoin d'utiliser ces informations issues de l'état. À l'heure "Mon, 11 Sep 2023 11:45:54 GMT
", des requêtes affluent à San Jose. Nous pouvons donc rediriger un nombre d'utilisateurs correspondant à 10 % des 150 emplacements disponibles pour San Jose, soit 15 utilisateurs.
Le compteur Durable Objects de San Jose continue de renvoyer la valeur actuelle du compteur pour chaque nouvel utilisateur atteignant le datacenter. Il incrémente la valeur de 1 après avoir communiqué avec une instance Workers ; par conséquent, les 15 premiers utilisateurs qui se présentent à l'instance Workers reçoivent une valeur de compteur unique. Si la valeur reçue pour un utilisateur est inférieure à 15, celui-ci reçoit un emplacement alloué au datacenter.
Lorsque les emplacements alloués au datacenter sont épuisés, les utilisateurs peuvent utiliser les emplacements alloués aux datacenters Anywhere, car ceux-ci ne sont pas réservés à un datacenter en particulier. Lorsqu'une instance Workers à San Jose reçoit un ticket indiquant une valeur de 15, elle déduit qu'il est impossible d'accéder au site web avec les emplacements alloués à San Jose.
Les emplacements Anywhere sont disponibles pour toutes les instances Workers actives dans le monde, c'est-à-dire 75 % des 150 emplacements restants (soit 113 emplacements). Les emplacements Anywhere sont gérés par une instance Durable Objects avec laquelle les instances Workers de différents datacenters peuvent communiquer lorsqu'ils souhaitent utiliser les emplacements Anywhere. Même si 128 utilisateurs (113 + 15 utilisateurs) se présentent à la même instance Workers pour ce client, ils ne seront pas mis en file d'attente. Cela augmente la capacité de Waiting Room à gérer un nombre non uniforme de nouveaux utilisateurs affluant vers des instances Workers dans le monde entier, aidant ainsi les clients à assurer la mise en file d'attente à des valeurs proches des limites configurées.
Pourquoi les compteurs sont-ils efficaces dans notre situation ?
Lorsque nous avons créé Waiting Room, nous voulions que les décisions concernant l'autorisation d'accès au site web soient prises au niveau de l'instance Workers elle-même, sans passer par d'autres services, pendant que la requête est en cours d'acheminement vers le site web. Nous avons fait ce choix afin d'éviter d'ajouter de la latence aux requêtes des utilisateurs. En introduisant un point de synchronisation au niveau d'un compteur Durable Objects, nous nous écartons de ce choix en introduisant un appel à un compteur Durable Objects.
Cependant, l'instance Durable Objects du datacenter reste dans le datacenter associé à celle-ci. Ceci permet d'obtenir une latence supplémentaire minime, généralement inférieure à 10 ms. Pour les appels à l'instance Durable Objects qui gère les datacenters Anywhere, l'instance Workers peut devoir traverser des océans et parcourir de grandes distances. Dans ce cas, la latence peut atteindre 60, voire 70 ms. Les valeurs au 95e centile indiquées ci-dessous sont plus élevées, en raison des appels transmis à des datacenters plus éloignés.
Graphique représentant la répartition des centiles des latences des compteurs depuis notre tableau de bord de production
La décision d'ajouter des compteurs ajoute une légère latence supplémentaire pour les nouveaux utilisateurs accédant au site web. Nous avons considéré que ce compromis est acceptable, car il permet de réduire le nombre d'utilisateurs mis en file d'attente avant que les limites ne soient atteintes. En outre, les compteurs sont uniquement nécessaires que lorsque de nouveaux utilisateurs tentent d'accéder au site web. Une fois que les nouveaux utilisateurs accèdent au serveur d'origine, ils sont directement admis par les instances Workers, car la preuve d'admission est disponible dans les cookies fournis par les clients, et nous pouvons les autoriser à accéder au site web sur la base de cette preuve.
Les compteurs sont des services très simples, qui effectuent un simple comptage et ne font rien d'autre. Ainsi, l'impact des compteurs sur la mémoire et le processeur est très limité. Par ailleurs, nous avons recours à de nombreux compteurs dans le monde pour gérer la coordination entre un sous-ensemble d'instances Workers, ce qui aide les compteurs à gérer efficacement la charge liée aux exigences de synchronisation des instances Workers Ensemble, ces facteurs font des compteurs une solution viable pour notre scénario d'utilisation.
Récapitulatif
Waiting Room a été conçu autour de notre priorité absolue : préserver le bon fonctionnement et la disponibilité des sites de nos clients, quel que soit le volume ou l'augmentation du trafic légitime. Waiting Room s'exécute sur tous les serveurs du réseau de Cloudflare, qui s'étend à plus de 300 villes dans plus de 100 pays. Nous voulons nous assurer que la décision d'autoriser l'accès à un nouvel utilisateur au site web ou de le mettre en file d'attente est prise avec une latence minimale, au moment opportun. Cette décision est difficile à prendre, car une mise en file d'attente trop précoce dans un datacenter peut entraîner une mise en file d'attente en dessous des limites définies par le client. À l'inverse, une mise en file d'attente trop tardive peut entraîner un dépassement des limites définies par le client.
Avec notre approche initiale, qui consistait à répartir équitablement les emplacements entre nos instances Workers, la mise en file d'attente était parfois effectuée précocement, mais nous parvenions à respecter assez efficacement les limites définies par les clients. Notre approche suivante, qui consistait à allouer un plus grand nombre de créneaux à un taux d'utilisation moins élevé (niveaux de trafic faibles par rapport aux limites définies par le client), nous a permis d'obtenir de meilleurs résultats dans les scénarios où la mise en file d'attente était effectuée en dessous des limites définies par le client, car chaque instance Workers disposait d'un plus grand nombre d'emplacements. Cependant, comme nous l'avons expliqué, cette approche rendait la solution plus susceptible de permettre un dépassement des limites lorsqu'un pic soudain de trafic se produisait après une période caractérisée par un faible taux d'utilisation.
Les compteurs nous permettent de bénéficier du meilleur des deux mondes, en évitant de répartir les emplacements en fonction du nombre d'instances Workers. Grâce aux compteurs, nous pouvons nous assurer que la mise en file d'attente n'est pas effectuée trop précocement ou trop tardivement par rapport aux limites définies par le client. Cette approche entraîne une légère latence pour chaque requête provenant d'un nouvel utilisateur ; toutefois, nous considérons que cette latence est négligeable, et qu'elle permet de proposer aux utilisateurs une expérience plus satisfaisante qu'une mise en file d'attente précoce.
Nous améliorons continuellement notre approche dans le but de nous assurer que la mise en file d'attente des utilisateurs se déroule toujours au moment opportun et, surtout, que les sites web sont protégés. Tandis que des clients toujours plus nombreux utilisent Waiting Room, nous en apprenons davantage sur les différents types de trafic, ce qui nous permet d'améliorer le produit pour tous les utilisateurs.