Dans les coulisses d’ArenaNet : analyse d’une panne du jeu

de L'équipe Guild Wars 2 le 15 juillet 2021

Bonjour ! Je suis Robert Neckorcuk, chef d’équipe plateforme chez ArenaNet. Mon équipe gère un certain nombre de services de réseau back-end pour la franchise Guild Wars® : serveurs de connexion, de discussion, sites Internet et d’autres encore. Nous travaillons de concert avec deux autres équipes, celle des opérations du jeu et celle de gestion des mises en production, et formons le groupe des services dit « back-end ». Nous collaborons également avec les équipes en charge du gameplay, des analyses, de l’assistance clientèle, etc. Cependant, notre principal objectif est d’assurer le bon fonctionnement des jeux et de leurs infrastructures. La franchise Guild Wars est reconnue pour son excellente disponibilité en ligne. Nous sommes très heureux du succès de notre infrastructure, mais nous avons également rencontré plusieurs défis. Aujourd’hui, je souhaite vous parler du dernier incident majeur que nous avons rencontré, et des leçons que nous en avons tirées pour que nous puissions améliorer notre engagement envers vous.

À 6 heures du matin, heure du Pacifique, le lundi 11 mai 2020, j’ai reçu un appel téléphonique. Croyez-moi que je n’ai pas eu à retrouver la date exacte, ce souvenir étant encore gravé dans ma mémoire. Notre équipe des opérations du jeu a reçu une notification indiquant qu’une base de données live de Guild Wars 2 était revenue à une version antérieure, que les joueurs recevaient des informations incohérentes de la part des serveurs, et que nos outils internes affichaient un grand nombre d’alarmes et d’erreurs liées.

Imaginez ma panique.

J’ai connu des lundis moins mouvementés. D’ailleurs, je préfère les lundis moins mouvementés. En me connectant sur mon poste de travail, j’ai rejoint mes collègues qui enquêtaient sur ce qui s’était passé et sur ce que nous pouvions faire pour remettre le jeu dans son état normal. Pour une équipe et une entreprise dont l’objectif est une disponibilité en ligne à tout moment, notre enquête a révélé notre pire cauchemar : nous devions mettre le jeu hors ligne pour restaurer les bonnes données. C’était la première fois que j’étais confronté à un incident de ce genre, et nous avons mis du temps à identifier quelles approbations étaient nécessaires. Un peu après 9 heures du matin, j’ai soumis des modifications désactivant les connexions au jeu et fermant les serveurs de Guild Wars 2 en Europe.

Itération permanente

Durant cette interruption du service, Guild Wars 2 s’est retrouvé hors ligne dans nos centres de données européens pendant un peu plus de 20 heures. Outre plusieurs événements de quelques minutes, la précédente mise à l’arrêt de Guild Wars 2 datait du 23 août 2016. S’il n’est jamais amusant d’avoir à gérer ces problématiques ayant un impact sur la disponibilité du jeu, nous nous servons de ces incidents comme des opportunités d’apprentissage pour améliorer notre infrastructure et nos processus. Notre processus d’incident est semblable à celui de nombreuses entreprises proposant des services live, tant dans le secteur du jeu vidéo qu’en dehors.

  • Identifier l’étendue du problème : se produit-il sur un serveur, dans un centre de données ou sur une version particulière ? Essayer de limiter notre enquête à un ensemble plus restreint de services ou de régions.
  • Identifier un cheminement permettant le fonctionnement du service le plus rapidement possible – il s’agit d’un compromis entre la correction et la disponibilité. Si nous faisons fonctionner le service en bricolant quelque chose, allons-nous casser autre chose ?
  • Une fois que le service fonctionne de nouveau, rédiger un rapport d’incident. Ce rapport doit détailler ce qui s’est passé, ce qui nous a informés du problème, les mesures que nous avons prises et les personnes touchées.
  • Plus tard, pendant les heures de bureau, organiser une réunion avec les principales parties prenantes pour examiner le rapport d’incident et créer des tâches pour tout élément de suivi. Les éléments d’action peuvent viser à améliorer les alertes ou la détection, à mettre à jour la documentation ou les processus automatisés, ou à créer un nouvel outil.

Nous examinons/modifions nos processus et procédures pas seulement lors des incidents. En 2017, ArenaNet a pris la décision de migrer son centre de données physique vers un centre de données sur le cloud à l’aide de l’infrastructure AWS (sans aucune interruption de service !). En 2020, après nous être adaptés au travail à distance, nous avons terminé la migration de notre pipeline d’analyse et de suivi d’un fournisseur matériel à un fournisseur cloud.

Ces migrations vers le cloud sont un gage de flexibilité : grâce à elles, nous avons constamment la possibilité de changer et de modifier notre infrastructure, rapidement et sans interruption. Début 2020, nous avons lancé une mise à niveau AWS interne et holistique, en examinant les coûts et les options pour chaque serveur que nous exploitons, de nos serveurs de développement commercial à nos serveurs de planification JcJ en direct. AWS propose constamment de nouveaux services et de nouveaux types de matériel, et nous n’avions pas effectué d’audit complet depuis 2017. Cette démarche nous permet d’apporter des changements à l’expérience des joueurs en jeu, d’adapter nos environnements de développement au jeu et d’améliorer plusieurs outils de back-end. Nous avons également mis à jour certains serveurs qui n’avaient pas été modifiés (ou même redémarrés) depuis notre migration en 2017 !

Lorsque l’on s’attaque à un projet de cette envergure, l’une des stratégies les plus efficaces consiste à le décomposer en petits éléments plus faciles à gérer, un peu comme découper une grande pizza ! Nous voulions revoir chaque instance AWS et heureusement, nous avions plusieurs « compartiments », ou différents types d’instances : les serveurs de jeu, les serveurs de bases de données, les serveurs commerciaux, etc. Notre objectif était de les analyser un par un, de procéder aux modifications, puis de passer au groupe suivant. Pour chaque série de changements, nous commencions par migrer nos serveurs de développement internes. Nous rédigions un dossier d’exploitation pour documenter le processus et vérifier le comportement, puis nous migrions nos environnements de test et live en suivant les étapes de ce dossier.

Pour n’importe quel produit et n’importe quelle entreprise, la possibilité d’itération est primordiale. Construisez quelque chose dans votre jardin, mettez votre création en pièces, cassez-la aussi souvent et de manière aussi bizarre que possible. Après avoir tout réparé en interne, votre création devrait être assez résistante lorsqu’elle sera exposée au public. Pour les équipes plateforme et opérations de jeu, ce processus de « nous entraîner comme nous jouons » est un autre outil qui profite à la qualité de notre service. Ceci étant dit, le serveur de développement et le serveur de jeu live diffèrent grandement en termes de coût et d’échelle. Ainsi, même si nous aimerions que tout se comporte de la même manière, ils sont tout à fait uniques.

Quelques informations (très simplifiées !) sur nos bases de données : nous avons deux serveurs, un serveur principal et un serveur secondaire. Lorsque nous interagissons avec la base de données, un message « appliquer cette modification » est envoyé à l’instance principale. Le serveur principal envoie ensuite ce même message au serveur secondaire (ou miroir), puis s’applique lui-même la modification. Si de mauvaises choses arrivent au serveur principal, la seconde instance prend automatiquement le relais et agit comme l’instance principale. Cela n’implique aucune indisponibilité et aucune perte de données. La nouvelle instance principale enverra des messages au « nouveau » serveur secondaire lorsqu’il aura récupéré de ses « soucis ». Pour mettre à niveau les instances, nous déconnectons manuellement les bases de données principales et secondaires, mettons à niveau le serveur secondaire, et reconnectons les deux.

L’un des points de données importants que nous pouvons suivre est le temps mis par le secondaire pour recevoir tous les messages en file d’attente de la part du principal, afin d’atteindre une parité des données. Associé à d’autres données de charge et de santé, cela peut nous indiquer si le serveur est en bonne santé ou non. Personnellement, je trouve ces données fascinantes. Nous échangeons ensuite de nouveau le principal et le secondaire, répétons le processus, et obtenons davantage de beaux graphiques, ainsi qu’un environnement mis à niveau.
Sur l’environnement de développement, tout s’est déroulé sans problème. L’environnement de test nous a permis de suivre de nouveau le processus dans son intégralité, et ce sans encombre. Nous avons lancé la mise à niveau du serveur live avec les serveurs européens le mercredi 6 mai 2020.

Rob et les vilains monstres

Le 6 mai, la mise à niveau s’est déroulée comme prévu. Nous avons déconnecté le serveur, mis le secondaire à jour, puis rétabli la connexion. Les messages de la file d’attente ont été copiés, nous avons échangé le principal et le secondaire, et avons répété ces actions une deuxième fois. La vitesse de copie des messages était un peu plus lente que celle de nos essais dans l’environnement de développement, mais la file d’attente était bien plus conséquente du fait du volume de trafic du jeu live.

Le jeudi 7 mai, nous avons reçu un message d’alarme indiquant que « le disque était presque plein ». Nous avions récemment créé des sauvegardes additionnelles des données, qui prenaient de la place, mais la solution adéquate semblait être d’étendre le volume du disque sans en tenir compte. Le volume de stockage ne coûte pas cher, et avec AWS, quelques clics de souris permettent de doubler la taille de notre disque de suivi et de sauvegarde. Un membre de l’équipe des opérations de jeu s’est servi de sa souris à plusieurs reprises, mais le volume étendu de stockage n’est jamais apparu comme par magie. Le vendredi, nous avons envoyé un ticket d’assistance à AWS, qui nous a recommandé un redémarrage pour corriger l’erreur. Dans la mesure où ce serveur était le principal, nous devions l’échanger avec le secondaire avant de le redémarrer.

Il est facile de constater a posteriori des erreurs qui semblent évidentes, mais à l’époque, il nous était impossible de deviner ce que nous ignorions alors. Le vendredi après-midi, nous avons tenté d’échanger le serveur principal et le serveur secondaire afin de procéder à un rapide redémarrage. Cependant, à ce moment, la file d’attente de messages du primaire au secondaire n’était pas vide, et continuait d’être copiée lentement. Après de rapides calculs, nous avons convenu que le disque dur ne se serait pas rempli au cours du week-end, et que nous pouvions revenir le lundi matin, nous occuper de la file d’attente de messages, échanger les serveurs et procéder au redémarrage.

Nous sommes bien revenus le lundi…

Nous avions bien remarqué que les messages de la file d’attente s’envoyaient lentement (imaginez une tortue), mais nous n’avons pas pris en compte la vitesse à laquelle la file d’attente grandissait (imaginez une tortue avec un jet-pack !). Rappelez-vous l’affirmation quelque peu exacte que si de « mauvaises choses » arrivent à la base de données principale, le serveur secondaire prendra automatiquement le relais en tant que nouvelle base de données principale… Il se trouve que l’une de ces « mauvaises choses » entraînant une erreur automatiquement est une croissance trop rapide de la file d’attente.

À 2 h 41 du matin le lundi 11 mai, le seuil de « mauvaises choses » a été franchi, et les bases de données ont été automatiquement échangées entre la principale et le miroir. Dans la mesure où les messages de mise à jour de la base de données étaient stockés dans une file d’attente sur l’autre serveur, lorsque les bases de données se sont interverties, les joueurs ont soudainement fait l’expérience d’un voyage dans le temps (et pas dans le bon sens), car l’ensemble de leur progression depuis le vendredi soir a été effacé. Après trois pénibles heures, à 5 h 40, l’équipe des opérations du jeu a été appelée en raison de l’augmentation du nombre de rapports de joueurs. J’ai été appelé à 6 heures du matin, et le jeu a été mis hors ligne à 9 heures.

Dès la mise hors ligne du jeu, l’une des premières choses que nous avons faites a été de redémarrer le serveur principal. Comme prévu, le volume de disque étendu est apparu ! Enfin une bonne nouvelle. Sur le disque fraîchement étendu, nous avons trouvé les données de sauvegarde les plus récentes contenant tous les messages de la file d’attente, depuis 2 h 41 du matin.

Il est toujours de bon ton d’effectuer des sauvegardes. Le volume de stockage est bon marché, la possibilité de récupérer des données est une garantie de tranquillité d’esprit, et il est très simple de programmer des sauvegardes automatiques. Cependant, restaurer les données de cette sauvegarde a été une autre histoire, car ce n’est pas quelque chose que nous faisons souvent. D’un côté, il n’y avait aucune charge sur les bases de données, donc nous pouvions tout supprimer et recommencer si besoin. D’un autre côté, le jeu était hors ligne, et nous ressentions une pression immense pour restaurer rapidement et efficacement les données afin de pouvoir relancer le jeu.

(Note : Je me concentre sur le fil conducteur de l’histoire, mais à ce stade, toute une série d’enquêtes annexes avait également été lancée sur l’impact plus large affectant le comptoir, la boutique aux gemmes, la création de nouveaux comptes, etc. Il s’est passé beaucoup de choses pendant cet incident, avec les contributions de nombreuses équipes. Je pense que je pourrais écrire un recueil de mini-récits à propos de ce seul événement !)

Pour être honnête, le processus de restauration était plutôt ennuyeux, puisque nous nous sommes contentés de suivre les normes. Quelques clics de souris dans l’outil de gestion, et le serveur s’est remis en route. Avant de commencer, nous avons dû copier le fichier de sauvegarde sur le deuxième serveur afin de nous assurer de restaurer les mêmes données sur les deux serveurs. Le serveur utiliserait alors le fichier de sauvegarde pour restaurer les bases de données. Ce processus a pris plusieurs heures. Ensuite, le serveur traiterait tous les messages enregistrés pour que les deux bases de données soient exactes à 2 h 41. Cela a également pris beaucoup de temps. Le premier serveur a terminé à 1 h 37, et le second à 4 h 30 le lendemain.

(Note 2 : Outre le travail à proprement parler, les personnes avec lesquelles vous travaillez sont probablement l’élément le plus important dans le choix d’une entreprise ou d’une équipe. Nous étions une poignée en ligne depuis 5 h 30 ou 6 h du matin, à ne faire que de petites siestes et à travailler jusqu’aux premières heures du lendemain. Nous avons dû littéralement veiller sur nos serveurs ! Si tout le monde a pris la situation au sérieux, chacun a su se contrôler tout en gardant une pointe d’humour pour nous aider à surmonter l’incident. Cette équipe est exceptionnelle dans ce qu’elle fait et la manière dont elle s’y prend !)

L’infrastructure de Guild Wars 2 est également incroyable. Elle est capable de se mettre à jour sans temps mort et dispose de nombreux paramètres pouvant avoir un impact sur différentes fonctionnalités ou sur différents contenus en jeu afin de lutter contre les exploitations de bugs et les plantages, ou même de modifier la difficulté d’événements dynamiques sans avoir à proposer de mise à jour ! Le 12 mai, nous avons utilisé une autre fonctionnalité du jeu que nous n’avions pas utilisée depuis 2016 : la possibilité de mettre le jeu en ligne sans le mettre totalement en ligne. Le jeu était alors complètement en ligne, mais seuls les développeurs pouvaient s’y connecter, et non les joueurs.

À 4 h 55 du matin, nous avons « relancé » le jeu, et un grand nombre de développeurs internes, d’analystes QA et quelques partenaires européens s’y sont connectés. J’ai été très impressionné de voir qu’en l’espace de quelques minutes, les joueurs se sont rendu compte que le jeu était en phase de test live et que leur progression de lundi matin avait été restaurée. J’imagine que c’est ce qu’il se passe lorsque l’on met nos API à disposition du public !

Après un test de l’environnement live qui a contrôlé la santé de la base de données et les files d’attente de messages, nous avons ouvert les serveurs au public à 5 h 37 du matin, plus de 20 heures après les avoir fermés. Toute l’équipe était heureuse de redonner la possibilité aux joueurs de retrouver ce monde qu’ils aiment tant, moi y compris. J’étais aussi content de pouvoir dormir quelques heures.

Ouf.

Après quelques heures de repos, nous nous sommes reconnectés pour essayer de comprendre l’origine de cette panne. Dans l’après-midi, une alarme s’est déclenchée sur nos serveurs européens : le volume de messages de la file d’attente de la base de données était trop élevé.

Flûte. Encore.

Nous avions correctement identifié et ajouté certains mécanismes d’alerte pour ces points de défaillance nouvellement découverts. Les deux jours suivants, nous avons géré manuellement la copie des bases de données, ainsi que les connexions entre le serveur principal et le serveur secondaire. Nous avons conversé avec des administrateurs de bases de données, des opérateurs réseau et nos responsables techniques de comptes chez AWS. Nous avons modifié chaque paramètre pouvant l’être concernant les files d’attente de messages, les volumes, le stockage et les suivis. Après plusieurs jours de lecture de documentation, de collecte d’informations auprès d’experts et de tentatives de modification, nous avons finalement trouvé la solution le vendredi.

Roulements de tambour !

La cause première était les pilotes.

Les pilotes permettent aux systèmes d’exploitation logiciels de communiquer avec les appareils connectés. Si vous avez des périphériques tels qu’une souris gaming ou une tablette graphique, vous avez probablement téléchargé des pilotes spécifiques pour ces appareils.
Dans notre cas, le système d’exploitation du serveur ne disposait pas de la dernière méthode de communication pour interagir avec le disque dur. Pas génial pour une base de données où la lecture et l’écriture de données sur le disque représentent 99 % de sa raison d’être… (Le 1 % restant est le facteur « ouah ». Ouah, vous avez une base de données ?! Cool.)

Lorsque nous avons mis nos serveurs à niveau, nous sommes passés de la 4e génération de serveurs AWS à la 5e génération. Ce changement a entraîné une modification de la manière dont les serveurs interagissent avec les appareils connectés (je ne comprends pas complètement comment le système fonctionne, mais AWS a trouvé un nom sympathique pour sa technologique sous-jacente : Nitro !). La version de notre pilote était ultérieure à la version de base proposée par AWS, donc nous ne nous attendions pas à des mises à jour additionnelles. De plus, cela n’a jamais posé problème dans nos environnements de développement. Cependant, ces derniers n’ont jamais supporté la même charge que les serveurs du jeu live. Nous étions vendredi, et découvrions les conséquences d’une mise à jour de pilote ratée, mais avons décidé d’aller de l’avant.
Comme précédemment, nous avons coupé la connexion entre les bases de données, avons procédé à la mise à jour de pilote, puis les avons reconnectées.

La file d’attente s’est vidée quasi instantanément.

La vitesse d’écriture des données mesurée était de 100 000 kilobits par seconde, contre 700 kbps auparavant.

J’ai souri, j’ai ri (sans pouvoir me contrôler).

Nous avons répété le processus sur l’autre serveur. Encore une fois, la file d’attente s’est vidée en une fraction de seconde.

J’ai bien dormi le week-end suivant. Et j’ai passé beaucoup de bons lundis matin depuis.

Un regard vers le passé et vers l’avenir

Voici donc ce qui s’est passé, ce que nous avons manqué et pourquoi cet incident s’est produit. Nous allons maintenant passer à ce que je préfère dans mon métier : quelles leçons en avons-nous tiré ? Comment nous en sommes-nous servi pour progresser et nous améliorer ? Quels amis avons-nous rencontrés le long du chemin ?

Tout d’abord, cet incident nous a rappelé à quel point l’environnement de développement et l’environnement live sont différents. L’environnement de développement est idéal pour s’exercer, enregistrer des mesures de performance spécifiques, etc. Cependant, pour certaines modifications, il est nécessaire d’utiliser des outils tels que le test de charge et le stress-test sur plusieurs machines.

Deuxièmement, cela nous a rappelé que nous devons toujours vérifier nos hypothèses et prendre du recul pour examiner la vue d’ensemble en cas d’imprévu. Nous avions fait tout comme il fallait dans les jours qui ont précédé la panne, mais nous nous sommes concentrés sur la mauvaise facette du problème. Poser des questions à quelqu’un d’autre nous aurait fourni une perspective différente et la nécessité de défendre l’irrégularité observée, afin de déterminer si elle pouvait ou non constituer un problème.

Le changement le plus important pour nos bases de données a été d’augmenter les alertes sur les paramètres clés de ces dernières, et pas seulement sur les paramètres système tels que le processeur ou l’espace des disques durs. Pour nos opérations live, nous avons créé un certain nombre d’alertes dans un outil tiers afin d’améliorer notre temps de réponse pour des problèmes futurs. Pour nos opérations générales, nous avons amélioré la tenue des registres de notre infrastructure AWS, en suivant désormais plus que les simples types d’instances. Nos registres indiquent désormais les types d’instances, la génération, les pilotes et les types de stockage. Nous avons élaboré un package commun à installer sur tous les nouveaux serveurs qui comprend des versions de pilote spécifiques. Ce package commun sera mis à jour à chaque plan de migration futur, afin d’éviter que ce problème ne se reproduise.

Nous avons procédé à la migration des instances de bases de données restantes et autres, offrant ainsi des performances plus élevées pour un service amélioré. Au cours des 14 derniers mois, nous avons relevé un taux de fonctionnement de 99,98 %, avec seulement 5 interruptions mineures affectant la connexion des joueurs.

Nos efforts continus visent toujours à vous offrir la meilleure expérience et la meilleure ergonomie pour nos services. Nous tenons à rendre hommage au design conçu par nos prédécesseurs, ainsi qu’aux outils et aux procédés que nous utilisons pour assurer une disponibilité de classe mondiale, et nous sommes heureux de voir notre indice de disponibilité actuel dépasser la barre des un an. Même si nous n’atteindrons peut-être jamais la perfection, nous nous efforcerons de le faire avec chaque procédure et déploiement futurs. Alors que nous attendons avec impatience les nouvelles fonctionnalités et les nouveaux projets que les équipes de conception et de jeu vous préparent pour Guild Wars 2, nous travaillons en permanence dans les coulisses pour nous assurer que vous puissiez toujours vous connecter et profiter du jeu.

Ouah, je savais que je pouvais écrire de nombreuses lignes de code, mais apparemment, je suis également capable de rédiger des articles de blog assez longs. J’espère que vous avez apprécié cette lecture. Certains attendaient cet article depuis longtemps, mais je suis très heureux de pouvoir partager ce genre d’histoires avec vous. Nous aimerions connaître votre avis et vos réactions sur ce type d’articles, c’est pourquoi nous avons créé un fil de discussion sur nos forums officiels !

À bientôt en Tyrie,
Robert