World of Warcraft

L’atelier de l’ingénieur : recréer l’effort de guerre d’Ahn’Qiraj

Blizzard Entertainment

La guerre est là. Plus tôt ce mois-ci, l’un des évènements les plus attendus de WoW Classic a commencé : l’effort de guerre d’Ahn’Qiraj. Des royaumes entiers ont uni leurs forces ; la Horde et l’Alliance ont combiné leur puissance pour réunir des ressources afin d’ouvrir les portes et débloquer les raids d’Ahn’Qiraj. Lorsque la guerre des Sables changeants a pris place pour la première (et unique) fois en 2006, dans chaque royaume, des milliers de joueurs ont chevauché ou volé vers Silithus pour prendre part au chaos ou y assister. La participation a dépassé toutes les espérances de l’équipe de développement, et pour le dire simplement, nous n’étions pas prêts. Les serveurs ont vite été surchargés, et 12 heures durant, de nombreux joueurs ont été entraînés dans une boucle de connexions, déconnexions et tentatives de reconnexion. Pendant ce temps, nos ingénieurs se démenaient pour corriger les problèmes et permettre aux joueurs de se reconnecter. Bien que nous ayons réussi à stabiliser les serveurs pendant l’évènement et que nous en ayons tiré quelques leçons, nous avons noté plusieurs points à améliorer. Quinze ans plus tard, nous étions prêts à recréer l’un des moments les plus épiques de l’histoire du jeu dans WoW Classic : nous avons mis l’accent sur l’optimisation des serveurs pour lutter contre la latence et éviter les plantages, et nous avons pu accueillir jusqu’à deux fois plus de joueurs en Silithus qu’à l’époque du premier évènement, en 2006.

Dans cet article, vous découvrirez comment nous avons pu recréer cet évènement très attendu ; nous vous expliquerons comment nous avons automatisé les tests de résistance et les tests ouverts aux joueurs pour repérer les points critiques et concevoir des solutions d’optimisation, comment nous avons trouvé des solutions logicielles pour remédier à des problèmes que le matériel ne pouvait pas résoudre, et comment nous avons mis en place un évènement mondial avec un minimum de plantages serveur tout en préservant l’expérience de jeu de WoW Classic.

Recréer la deuxième guerre des Sables changeants

Nous avions trois objectifs spécifiques pour la mise en place de cet évènement : prévenir les plantages en série, augmenter les limitations de joueurs dans la zone et déterminer la latence maximale tolérable avant de téléporter les joueurs hors de Silithus. Avant d’entrer dans les détails de l’optimisation des serveurs, il est important de comprendre les contraintes dont nous devons tenir compte : les limitations de la base de code de WoW Classic, le fonctionnement des solutions de gestion de la population des serveurs, et leur effet sur l’expérience de jeu.

Les Anubisath envahissent Azeroth

Dépasser les limites

La version moderne de World of Warcraft a été bâtie sur les fondations de la base de code originale, publiée il y a 15 ans. Depuis le lancement du jeu, nous avons développé des solutions plus modernes pour gérer les pics d’affluence dans Battle for Azeroth, et notamment le sharding. Les shards permettent aux serveurs de World of Warcraft d’accueillir bien plus de joueurs que ce qui était possible en 2006. Dans Battle for Azeroth, ils nous servent à gérer la charge des serveurs en créant une copie d’une zone (Zuldazar, par exemple) lorsque le nombre de joueurs dépasse un certain seuil. Ceci neutralise les problèmes de latence en distribuant les joueurs entre différentes versions d’une même zone, car les interactions entre joueurs comptent parmi les plus intensives pour les processeurs en raison du nombre de paquets qu’elles envoient constamment au serveur afin de permettre aux déplacements et aux sorts des joueurs d’être précis. En outre, le sharding prévient les potentiels problèmes de latence qui peuvent se produire lors du passage dans une nouvelle zone où le nombre de joueurs dépasse le seuil. Le principe semble simple, mais il y a un piège : WoW Classic est conçu pour être une reproduction authentique des données du jeu original dans sa version 1.12, ce qui implique de conserver ses particularités de gameplay. Dans de rares cas, les shards peuvent faire disparaître votre proie (personnage-joueur ennemi ou PNJ) lors du passage dans une nouvelle zone. Conserver le sharding nous aurait empêchés de revivre ces moments de jeu où nous pourchassions des joueurs et des PNJ d’une zone à l’autre. Il nous fallait donc trouver une solution qui, sans interférer avec le gameplay original, nous permette d’accueillir plus de joueurs sur un serveur sans entraîner une latence démesurée.

Pour remédier à ce problème, nous avons choisi d’utiliser des layers, des copies de régions entières (les royaumes de l’Est, par exemple) destinées à réguler la population de joueurs et les problèmes de latence tout en conservant le charme mémorable du jeu original, afin que les joueurs puissent continuer d’attirer les boss hors instance d’une zone à l’autre et pourchasser les joueurs adverses au-delà des frontières d’une région sans risquer d’être réassignés à un shard différent. Cela étant dit, les layers ont été pensés comme une solution temporaire. La version 1.12 originale n’utilisait ni sharding, ni layering ; nous avons donc promis aux joueurs que nous n’utiliserions les layers qu’au lancement de WoW Classic et que ceux-ci disparaîtraient progressivement une fois les utilisateurs mieux répartis entre les différentes zones du jeu. Nous continuons d’utiliser le layering dans quelques cas particuliers où les joueurs sont extrêmement nombreux (sur Faerlina en Amérique du Nord, par exemple), mais nous avons réduit le nombre de layers actifs sur ces royaumes depuis la sortie du jeu. Quinze ans après les évènements originaux, la guerre d’Ahn’Qiraj est l’un des évènements les plus attendus de WoW Classic, et nous nous attendions à battre des records d’affluence dans une même zone (en dehors des zones de départ à la sortie du jeu), et tout cela sans layers pour gérer la situation. Sans les technologies de layering et de sharding, nous avons dû faire preuve de créativité, et vite.

Les joueurs se rassemblent autour du gong

Concevoir une expérience inoubliable

Nous avons entrepris de réguler la population de joueurs sans layering ni sharding en générant des « clients sans tête » (des joueurs automatisés) et en leur ordonnant d’imiter de vrais joueurs, par exemple en lançant des sorts, en combattant des PNJ et en se déplaçant dans la zone. Cela nous a permis d’avoir un aperçu des performances du jeu avec des milliers de joueurs en train d’interagir dans une même zone. Après ces simulations, nous avons organisé des tests de résistance avec des volontaires pour observer des comportements réalistes et les comparer aux résultats précédents. Nous avons ainsi découvert certains points critiques et identifié les parties du code de nos serveurs qui rencontraient le plus de problèmes en cas de forte affluence. Les délais de réponse du serveur ont été examinés de près pour déterminer s’ils étaient proches d’entraîner un blocage, c’est-à-dire une absence de réponse du serveur.

L’étape suivante consistait à analyser ce qui affectait les performances du serveur afin de commencer à diviser cette tâche monumentale en objectifs plus simples. Nous avions affaire à un problème polynomial : impossible de le résoudre avec un matériel plus rapide, car celui-ci ne fait pas augmenter les performances de manière exponentielle. Au lieu de cela, nous avons dû réaliser l’optimisation manuellement en choisissant quelles données devaient être communiquées aux joueurs et quand. Pour illustrer ce casse-tête, imaginons que 20 joueurs sautent dans un cercle. Le serveur relaie les actions de chaque joueur aux 19 autres grâce à des paquets de données. Dans le cas de ce groupe de 20, le serveur traite 380 paquets (20 joueurs totaux * 19 destinataires = 380 paquets). Le problème s’amplifie lorsque davantage de joueurs réalisent la même action dans la zone. Dans notre exemple, si nous passons à 500 joueurs, ce sont 249 500 paquets qui sont envoyés par le serveur. Avec 1 500 joueurs, on atteint 2 248 500 paquets. Selon les actions des joueurs, plusieurs sont envoyés à chaque seconde ; gardez à l’esprit que les exemples ci-dessus n’impliquent qu’une seule action. Plus le serveur reçoit de paquets, plus il doit consacrer de temps à un joueur avant de gérer les actions des autres joueurs. Quand le problème s’intensifie, les serveurs approchent du blocage. Dans WoW Classic, chaque royaume compte bien plus de joueurs qu’en 2006, et nous nous attendions donc à accueillir plus de joueurs que jamais aux alentours des portes.

Optimiser les performances des serveurs

Nos serveurs étant conçus pour planter et redémarrer en cas de blocage, nous savions qu’il était essentiel de faire tout notre possible pour minimiser les temps de calcul. Après quelques tests, il est apparu que les déplacements étaient le premier facteur entraînant une lourde charge pour nos serveurs. Nous avons commencé par abandonner les mises à jour d’orientation (qui indiquent dans quelle direction un modèle de personnage est tourné) pour n’en envoyer qu’au début et à la fin d’un déplacement, et pendant un mouvement au clavier. Avec autant de joueurs, la latence était déjà compromise, et consacrer du temps de calcul à l’envoi de mises à jour d’orientation mineures nuisait à la fidélité de l’expérience. Il valait donc mieux arrêter de les envoyer. Nous avons choisi de limiter la fréquence d’envoi des mises à jour de déplacement pour pouvoir accueillir plus de joueurs dans une même zone. Gardez à l’esprit que nous essayons de déterminer le point critique avant le plantage des serveurs tout en essayant d’accueillir un maximum de joueurs en Silithus. Après tout, il vaut mieux manquer quelques mises à jour de déplacement plutôt que de ne pas pouvoir se connecter du tout. Nous avons également commencé à ralentir les données considérées comme moins prioritaires. Une action considérée comme « moins importante » ne devrait pas être traitée à la même vitesse que des actions « plus importantes ». De nombreux messages étaient envoyés simultanément quelle que soit leur importance, et nous avons optimisé le code pour ne vous envoyer les informations moins importantes que par lots, et moins fréquemment.

Les améliorations et affaiblissements affectaient également les performances de manière significative. Dans le monde du jeu, surtout lorsque vous combattez des monstres, des améliorations et affaiblissements sont constamment appliqués aux unités. Cela peut sembler insignifiant, mais quand de nombreux joueurs sont proches les uns des autres, cette information doit être transmise à tous. Comme pour les données peu prioritaires, nous regroupons désormais les améliorations et affaiblissements pour éviter d’envoyer plusieurs paquets successifs aux joueurs.

Gérer les populations de joueurs

Au-delà de la nécessité d’optimiser les serveurs pour accueillir plus de joueurs dans chaque zone, il ne nous a pas échappé qu’il serait impossible de faire tenir la population d’un royaume entier (plus du double de la population d’un royaume de la version 1.12 du World of Warcraft original) dans la région de Silithus. Il a fallu prendre des décisions difficiles et limiter l’accès à la zone à certaines catégories et un certain nombre de joueurs. Nous avons décidé de n’accueillir que les personnages de niveau 60 en Silithus et de cesser de faire entrer les personnages admissibles une fois la zone pleine. Cette restriction nous semblait judicieuse, car l’évènement de Silithus est du contenu de niveau maximum, et les personnages de plus faible niveau peuvent tout de même participer à l’effort de guerre dans d’autres zones, en tuant par exemple les Anubisath qui rôdent dans les Tarides, une zone destinée aux joueurs de niveau 20 à 30. D’autre part, nous savions combien de joueurs nous pouvions accueillir dans une zone sans faire planter le serveur, mais un point de friction demeurait : de combien réduire ce nombre pour atteindre le meilleur ratio performances/population ? Avec les tests, nous avons déterminé que ce nombre était d’environ 1 500 joueurs lorsque ceux-ci étaient regroupés. Toutefois, étant donné que l’évènement s’étend à toute la zone, nous n’avons constaté qu’un impact minime sur les performances une fois les joueurs dispersés.

L’évènement étant censé avoir lieu dans toutes les régions, nous devions veiller à ce qu’il fonctionne sur plusieurs layers. Autrement dit, il fallait qu’un porteur du sceptre puisse démarrer l’évènement dans tous les layers du royaume en sonnant le gong. Le début de l’évènement étant lié à une interaction de joueur, nous devions nous assurer que le porteur du sceptre soit visible par les joueurs de tous les layers. Cette nécessité créait un problème intéressant : les serveurs devaient relayer une information qu’ils ne communiquaient pas en temps normal. Beaucoup de complications peuvent en découler : il faut compiler et envoyer les mises à jour aux serveurs pour communiquer les mêmes données sur plusieurs layers, et potentiellement à des milliers de joueurs.

Nous avons commencé à développer cette technologie avec le concours de pêche de Strangleronce et nous l’avons appliquée par la suite aux améliorations mondiales d’Onyxia, Nefarian, Zul’gurub et Rend. Une fois satisfaits de son fonctionnement, nous étions prêts à la tester avec les autres technologies de l’évènement d’Ahn’Qiraj.

Joueurs de la Horde en Silithus

Expérimentation et solutions

Maintenant que nous avions résolu les principaux problèmes techniques et mis en place plusieurs moyens d’optimiser les performances des serveurs, il était temps de tester le tout. Nous avons créé une version plus courte de la guerre de 10 heures en la ramenant à une heure.

Pendant le premier test de résistance, nous avons autorisé presque tous les joueurs à entrer dans la zone pour voir ce qui allait se passer. À un moment, nous étions presque à 150 % de la capacité d’un royaume de l’époque de la 1.12. C’est à cet instant que le royaume de test a planté. Nous savions que nous avions fixé une valeur très élevée pour le nombre maximum de joueurs présents dans la zone, mais nous observions une population qui dépassait largement ce seuil. Nous avons enquêté sur le problème et réalisé que le code qui permettait le transfert des joueurs dans et hors d’une zone employait une file d’attente incapable de traiter de nombreux joueurs à la fois. Cela expliquait pourquoi certains joueurs n’étaient pas téléportés hors de la zone ou bloqués en plein trajet aérien pendant une durée inhabituelle. Nous avons rétabli le serveur et poursuivi le test de résistance en effectuant des ajustements au fur et à mesure. Nous avons progressivement abaissé la limite de joueurs jusqu’à atteindre un point où le jeu conservait une certaine latence, mais restait à peu près jouable et accueillait beaucoup plus de joueurs que toute autre zone auparavant. L’évènement n’était censé durer qu’une heure et demie, mais à cause des plantages, le test a finalement nécessité quatre heures.

Le deuxième test de résistance a eu lieu une semaine plus tard. C’était l’occasion de voir si nos optimisations fonctionnaient. Dès le début du test, nous avons constaté plusieurs améliorations : les joueurs n’étaient plus bloqués sur les trajets aériens à destination de Silithus ! Nous avons pu obtenir assez de données pour déterminer combien de joueurs nous pouvions accueillir sans problème en Silithus. À l’issue de ces deux tests, nous avons fixé des valeurs en cherchant le meilleur compromis entre gestion de la latence et stabilité des serveurs. Ces tests nous ont permis de vérifier le résultat de nos optimisations, et nous considérons que chaque évènement a été un succès, car nous avons pu identifier les limitations de la zone et les ajuster.

Étendre les solutions serveur à tout Azeroth

À l’origine, les optimisations ne devaient être actives qu’en Silithus pendant la guerre des Sables. Lorsque nous avons été certains de pouvoir les appliquer de manière globale, nous les avons étendues au monde entier dans la mise à jour 1.13.5. Une fois l’effort de guerre initié, les joueurs ont commencé à livrer des fournitures et à récolter d’innombrables cadavres d’insectes. Nous avons observé d’importants pics d’affluence en Silithus, mais aussi dans les capitales et les zones extérieures. Ces optimisations ont contribué à améliorer les performances de ces expériences et permis à d’ambitieuses batailles JcJ de se dérouler en Azeroth. Certains joueurs sont même allés jusqu’à faire apparaître le boss hors instance Thunderaan pour déloger l’autre faction d’une ruche.

Bien que l’évènement d’ouverture des portes n’ait pas encore commencé, certains serveurs rencontraient des problèmes étranges qui empêchaient leur effort de guerre de progresser. La vitesse à laquelle certains serveurs terminaient leur effort de guerre était si importante qu’elle créait une situation de compétition critique dans le traitement de chaque livraison, ce qui pouvait empêcher le début du décompte de cinq jours. Ce cas de figure étant très rare, nous avons pu débloquer ces serveurs manuellement, puis corriger le problème pour les prochains royaumes à terminer leur effort de guerre.

Une fois les efforts de guerre terminés et le délai de cinq jours écoulé, nous avons commencé à observer les royaumes chinois, qui ont été les premiers du monde à ouvrir les portes. Le premier serveur chinois à activer le gong était Ouro. En étudiant la population des différents layers, nous avons constaté que sur chaque layer, la plupart des joueurs étaient en Silithus. Nous n’avions encore jamais organisé d’évènement sur plusieurs layers à pleine capacité accueillant plusieurs milliers de joueurs. Malgré une latence perceptible, nos serveurs n’ont rencontré aucun plantage pendant l’ouverture des portes sur les premiers royaumes chinois.

Sonnez le gong !

Le 4 août, nous avons remarqué plusieurs royaumes nord-américains sur le point de sonner le gong, peu après la réinitialisation des serveurs. Nous avons activement surveillé chacun de ces royaumes grâce aux comptes des Maîtres de jeu et à nos outils d’observation afin de détecter et de résoudre tout problème éventuel. Chaque royaume a ouvert les portes et commencé l’évènement sans problème. Les porteurs du sceptre ont reçu leur prestigieuse monture Char d’assaut qiraji noir, les joueurs ont pu affronter des insectes encore plus gros ; nous étions satisfaits de la stabilité de l’expérience. Alors que nous attendions que le premier serveur post-réinitialisation arrive au bout de son délai de cinq jours, nous avons détecté un problème majeur : les évènements ne persistaient pas après un redémarrage. Autrement dit, en cas de plantage ou de redémarrage du serveur, toute la progression de l’évènement était perdue. Bien que ce problème date du début du développement de WoW Classic, il était rare qu’un évènement ait besoin de se poursuivre après le redémarrage du serveur. Notre équipe a rapidement résolu le problème, mais nous avons dû veiller à ce qu’aucun autre redémarrage ne se produise avant que nous ayons déployé un correctif et sauvegardé tous les efforts de guerre en cours dans notre base de données, le tout sans interrompre les joueurs.


Certains pensent que ce sont les plantages des serveurs qui ont rendu la première guerre d’Ahn’Qiraj si chaotique, et par conséquent mémorable. Nous avons toutefois préféré cultiver cette même ferveur en créant une expérience beaucoup plus stable, partagée avec environ 1 500 joueurs en Silithus au même instant sur chaque serveur. Nous voulions que la guerre d’Ahn’Qiraj de WoW Classic marque les mémoires en permettant à un maximum de joueurs de participer à un évènement de 10 heures sans interruption. Même si quelques royaumes ont planté, nous avons pu les relancer assez vite. Quelques minutes plus tard, tout était complètement rétabli, et aucun plantage n’a eu lieu par la suite.

Plus de 4 000 joueurs du monde entier sont devenus des seigneurs scarabées, et ce nombre continue de grimper à mesure que d’autres serveurs progressent dans leurs efforts de guerre. L’enthousiasme et la participation des joueurs de WoW Classic depuis le début de l’effort de guerre d’Ahn’Qiraj sont extraordinaires, et nous remercions tous ceux qui nous ont rejoints pour la deuxième guerre des Sables changeants !