/ Dev

🎮 Hexamaster - Architecture serveurs

Vous vous demandez comment fonctionne mon serveur ?
Vous cherchez des réponses pour faire le vôtre ?
Vous êtes juste curieux ?

Dans cet article je vais vous dévoiler comment j'ai conçu "l'architecture" de mes serveurs pour Hexamaster. Un jeu que je voulais "au départ" concentré sur le multijoueur.

Avant d'entrer dans "ma techno" je vais un peu parler de l'état de l'art sur le marché du jeu vidéo.

PS: Cet article contiendra beaucoup de termes techniques de différents milieux, je ferais mon possible pour essayer de traduire ça !

Dans le monde du jeu vidéo

Qui dit multijoueur dis plusieurs personnes en même temps.
De ce fait on a plusieurs façons de voir et prévoir les choses:

  • on fait le truc le plus simple/léger/pas cher possible et puis quand ça va plus on essaye d'améliorer ça
  • on prévoit un ensemble robuste, voir on prévoit "le buzz"

Pour avoir une comparaison simple, pour le jeu PUBG ils ont choisi la méthode 1, le succès du jeu les as dépassés et depuis le début leurs serveurs croulent sous la quantité de joueurs (aujourd'hui ça va mieux, mais ils perdent des joueurs aussi donc est-ce que les serveurs sont aujourd'hui suffisant pour le monde qu'il y avait l'an dernier ? On ne le saura sans doute jamais). pubg-down

Et prenons donc l'opposé: Fortnite (qui ont probablement profité de la hype de PUBG pour se "douter" du monde qu'ils auraient) qui lui a eu bien moins de problèmes. fortnite-down

Ok donc quand on "m'entends" parler il n'y a "que des problèmes avec les serveurs". Oui c'est vrai.
Quand un jeu rencontre un gros succès, les serveurs sont rarement capables d'amortir le choc, des fois un petit peu, mais souvent pas assez.

Et pour causes plusieurs raisons je pense :

  • manque d'expérience des programmeurs serveurs
  • méthodes de réalisation des serveurs trop "basique" (1 serveur pour X joueurs)
  • pas de scaling dynamique (architecture beaucoup plus complexe à mettre en place pour un jeu temps-réel)
  • pas de monitoring suffisant donc zéro anticipation

Pour faire plus simple, je dirais que l'industrie du jeu vidéo n'est pas assez "à la page" question technos serveurs.
On a amélioré sans cesse nos méthodes de productions de rendering, mais question "comment faire un serveur" ça n'a pas bougé (presque pas) alors que les technos elles, sont là ! (queueing, dockerisation, micro services).

Je ne dis pas que tout est simple au contraire même, les serveurs c'est probablement le truc le plus "hypothétique" qui soit.
server_meme

Et pour causes, beaucoup de problèmes peuvent apparaîtres:

  • serveur qui crash
  • base de données qui crash
  • connexion de l'utilisateur instable
  • connexion de l'utilisateur qui plante
  • utilisateur qui tente une action plein de fois
  • 10 utilisateurs qui tentent une action en groupe plein de fois
  • trop de personnes qui demandent à se connecter d'un coup
  • etc..

Bref, faire un serveur indestructible semble (est, soyons honnêtes) impossible.
Mais une chose est certaine à mes yeux, c'est que les efforts mis en place par les équipes pour faire des serveurs robustes sont bien trop faibles.

En tout cas, en ce qui concerne les jeux PC "mainstream". (car aussi étonnant que cela puisse paraître, pleins de jeux indépendant ou de jeux mobiles se portent très bien et n'accusent pas autant de lacune sur les serveurs).

Lexique

Un lexique s'impose pour être certain de comprendre la suite.

  • quand on dit "serveur" ou "serveur de jeu" on parle du serveur qui exécute le serveur du jeu, avec les algorithmes, la logique du jeu etc...
  • serveur de queuing (ou message broker): un serveur qui récupère des messages et les redistribues ou génère des files d'attentes en attendant que d'autres serveurs les récupères
  • serveur de base de donnée: permet de stocker des données plus ou moins complexes, de manière durable et sécurisée
  • serveur clé valeur: un serveur de base de données très simples qui ne peut stocker qu'une faible valeur, généralement destiné à faire transiter une information très rapidement
  • clustering: le fait de pouvoir instancier plusieurs fois le même serveur (on en fait des clones) qui travaillent tous de paires
  • scaling: le fait d'augmenter le nombre de serveur
  • micro-service: le fait de faire plusieurs serveurs de jeu qui traiteront chacun un aspect différent (l'opposé à cette méthode est le monolithe, on fait un serveur qui fait tout)

Les serveurs de Hexamaster

Maintenant que vous avez un peu une vision d'ensemble je vais vous détailler comment j'ai fait mes serveurs.

Alors, déjà j'ai dit "mes", je ne fais donc pas un serveur monolithe non-clusterisé non-scalable (comment ça j'ai abusé sur cette phrase ? 😂)

Sachant que ma communauté "déjà existante" est pas très grande, j'aurai tout à fait pu faire "un serveur pourri", cela serait resté cohérent et "fiable".

Mais après l'expérience "Pokewebgo" (et le serveur qui crash 4h après sont lancement), j'ai voulu taper le plus haut possible dans ce que je pouvais faire niveau architecture et technique.

Bien entendu, rien ne me garantit que mon travail aura été "utile" si on a aucun/peu de joueur (ce qui est le cas jusqu'à présent, mais le jeu n'est pas fini donc...pas d'pression).

Je me suis donc penché sur plusieurs idées, pour créer une puissante architecture serveur scalable à souhait et en temps réel (voir automatique en suivant l'affluence de joueur).
Et j'en suis donc venu à une idée que j'avais eue auparavant, faire une architecture micro-service, scalable, avec un serveur central de base de données et un cluster de serveurs clés/valeurs + broker.

Ce qui donne au minimum:

  • 6 serveurs NodeJS (serveur de jeu en micro-service)
  • 1 serveur MongoDB (base de données)
  • 1 serveur Redis (serveur clé/valeur + message broker)

J'ai précisé au minimum puisque tout est scalable.

Voilà un petit schéma des serveurs pour rendre tout ce tralala plus comestible: schema-archi

Ce qu'il faut comprendre, c'est que chaque serveur est libre de discuter avec Mongo (la base de données) ou Redis quand ça lui chante !
Le truc c'est de réussir à "contraindre" chaque service à un type de donnée afin d'éviter les éventuels conflits (ce qui se solderait par une perte d'objets par exemple, pour le joueur).

Voilà maintenant un exemple de quel bouton fonctionne avec quel serveur dans le jeu (ce n'est pas tout à fait ça mais c'est pour "illustrer"). schema-game De cette manière, chaque interaction concernant l'inventaire, appellera le service "inventory". Le Matchmaking quand on veut jouer en ligne contre quelqu'un, le solo lorsqu'on joue seul, etc...

Vous remarquerez que sur mon dernier schéma on ne voit ni le serveur "authentification" ni "Versus" et c'est normal, l'authentification n'est appelé que lors de la connexion/déconnexion (en gros) et le versus est appelé par Matchmaking qui vous fait transiter une fois la partie prête !

De son côté, Redis s'occupe de sauvegarder les informations des parties en cours et des personnes connectés. Redis assure aussi l'échange de messages entres plusieurs instances de serveurs soit le schéma suivant:
servers-redis Traduction: le serveur A dit à Redis "jouer la carte sur la case 1", Redis transmet le message à tout le monde, tout le monde exécute "jouer la carte sur la case 1".

Cela se traduit par les avantages suivants:

  • si le serveur d'authentification plante, tous les joueurs déjà connectés pourront continuer de jouer sans aucun problème
  • si le serveur "matchmaking" plante, uniquement les joueurs voulant lancer une partie en ligne seront impactés
  • si le serveur shop plante, les achats seront impossibles
  • etc...

Sans oublier que:

  • chaque serveur peut se répliquer à l'infini, donc seul les joueurs d'une instance d'un serveur seront impactés en cas de crash

Et là ça change tout.
On reprend notre précédent schéma et on y ajoute le joueur Toto qui joue sur le serveur A, contre Tata sur le serveur C. servers-toto-1-1

Le serveur B plante pour une raison inconnue, Toto et Tata ne sont pas impactés car ils n'ont pas à se soucier des autres serveurs. servers-toto-2-1

Le serveur A ou C plante, Toto et Tata sont impactés servers-toto-3-1
Mais si Toto jouait sur le serveur B, il n'y aurait pas eu de problèmes.

Côté code, ce qu'il faut retenir c'est que j'ai 6 serveurs différents.
D'un côté c'est bien car j'ai moins de choses par projet et c'est plus facile à déboguer (si l'inventaire plante je vais pas chercher dans le matchmaking !)
D'un autre côté je suis obligé d'avoir des doublons de code (problème que j'ai résolu en faisant une dépendance commune à tous mes serveurs) et de lancer une myriade de serveurs pour tout tester !

Cf une photo avec tous les serveurs de lancés pic-servers

J'oubliais presque de parler de l'hébergement.
Il va s'en dire que des serveurs "micro-services" c'est plus compliqué à héberger quand les besoins du jeu sont petits.
On ne ressent la puissance de cette architecture que lorsque des centaines, des milliers même ! De joueurs se connectent en même temps pour "la première fois".

Dans mon cas de figure j'utilise "scalingo", l'avantage c'est que c'est "tout fait" facile à utiliser et puissant.
Maintenant il est clair que pour lancer son prototype a 6 serveurs ce ne sera pas cadeau (le total des serveurs me coûte env 90€/m lorsque tout est lancé, heureusement on peut très facilement les éteindre et ainsi réduire sa facture).

Peut-être un "kimsufi" sera largement suffisant pour mener vos tests, mais le moment venu ne lésignez pas et choisissez bien !

Pour conclure cet article, comprenez que si vous arrivez à faire des serveurs "micro-services" cela pourra avoir un gros impact positif sur votre jeu.
Vous n'impacterez pas tous vos joueurs pour le moindre petit problème et en plus il sera plus facile de traquer et patcher l'origine d'un problème.

J'aurai pu rentrer dans la technique pure, dans le code, mais je pense que je me serais éloigné du sujet et que cet article aurait été moins accessible et qu'il n'aurait pas vraiment traité le sujet critique "l'architecture".

Si vous savez coder il vous sera assez facile de trouver de la documentation avec les termes que j'ai utilisés ici, de trouver des exemples et de mettre ça en pratique !

J'espère que cet article vous a plu et que vous avez appris des choses.
Peut-être un article plus technique la prochaine fois ?

Inateno

Inateno

Hey salut ! Je suis créateur de jeux vidéo et bricoleur fou ! Objectif: faire ce qui me passe par la tête. Ah, et je suis pas super bon en rédaction 😂

Read More