aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Serveur de Jeu

Serveur Auth de Jeu : Séparer Login et Game Server

Le premier vrai pas vers une architecture de jeu en ligne évolutive est généralement celui-ci : séparer le serveur auth de jeu du serveur qui fait tourner le monde du jeu lui-même. Quand un seul processus tente de vérifier les mots de passe des joueurs entrants tout en traitant simultanément le déplacement, le combat et l'inventaire de milliers de personnages, le moindre pic de trafic fait tomber le monde entier. La solution consiste à déplacer l'authentification vers un login server distinct et la logique de jeu vers un ou plusieurs game servers.

Ce que fait réellement le serveur auth

Le serveur auth (login server) est le gardien qui vérifie l'identité d'un joueur et lui accorde le droit d'entrer dans un monde de jeu. Dans un flux typique, ses tâches sont :

  • Authentification : il vérifie le nom d'utilisateur et le mot de passe (sous forme hachée) dans la base de données.
  • Statut du compte : il applique les bans, l'abonnement/paiement, les limites d'âge et les listes noires d'IP/matériel.
  • Liste des serveurs : il montre au joueur quels mondes (realms/canaux) sont ouverts et à quel point ils sont remplis.
  • Émission du jeton de session : en cas de connexion réussie, il génère un session token à usage unique et à courte durée de vie, puis le transmet au game server.

Le point crucial : le serveur auth se retire dès que la connexion est terminée. Une fois dans le monde, le joueur ne parle plus au serveur auth ; tout le trafic temps réel va au game server.

Pourquoi les séparer : les problèmes d'un seul serveur

Garder le login et la logique de jeu dans le même processus semble simple au début, mais cela entraîne plusieurs problèmes fondamentaux :

  • Profils de charge très différents : le login est court mais gourmand en CPU (vérification du hash du mot de passe) et dépendant de la base de données ; la boucle de jeu a besoin d'un trafic réseau constant et à faible latence. Les mettre dans le même pool de threads signifie qu'une vague de connexions en soirée crée du lag pour tous ceux qui jouent déjà.
  • Surface de sécurité : les mots de passe et les données de compte sont les actifs les plus sensibles. Les garder dans un processus séparé aux règles de sécurité plus strictes, isolé de la logique de jeu, réduit la surface d'attaque.
  • Point unique de défaillance : si un game server plante, seul ce monde est touché ; mais si tout est dans un seul processus, un seul crash bloque tous les joueurs, y compris ceux qui voulaient seulement se connecter.
  • Évolutivité : un seul serveur auth peut alimenter des dizaines de game servers derrière lui. Quand le nombre de joueurs augmente, vous ajoutez des game servers, sans devoir dupliquer l'infrastructure de login.

Poignée de main (handshake) basée sur un jeton

La communication sécurisée entre login et game server passe par un jeton de session. Le flux classique : le joueur se connecte au serveur auth, le serveur auth génère un jeton à courte durée de vie et le donne au joueur et (via une base partagée ou le réseau interne) au game server, le joueur se connecte au game server avec ce jeton, et le game server le valide.

// Serveur auth : émettre un jeton en cas de connexion réussie
Token issueSession(uint32_t accountId) {
    Token t;
    t.value   = randomBytes(32);        // imprévisible
    t.account = accountId;
    t.expires = now() + seconds(30);    // durée de vie courte
    t.used    = false;
    db.storeSession(t);                 // écrire dans la table partagée
    return t;
}

// Game server : valider le jeton à la connexion du joueur
bool verifySession(const std::string& token, uint32_t accountId) {
    auto s = db.loadSession(token);
    if (!s || s.used || s.account != accountId) return false;
    if (now() > s.expires) return false;   // expiré
    db.markUsed(token);                     // usage unique
    return true;
}

Les propriétés clés : le jeton doit être imprévisible (aléatoire cryptographique), à courte durée de vie (quelques secondes) et à usage unique. Ainsi, même intercepté, la fenêtre est minuscule. Le mot de passe n'atteint jamais le game server ; le game server ne discute de mots de passe avec personne, il ne valide que des jetons.

Base de données et état partagé

Comment les deux serveurs communiquent-ils ? L'approche la plus courante est une base de données partagée (généralement MySQL) : les comptes, les sessions et les données de personnages vivent dans des tables centrales. Le serveur auth lit la table des comptes et écrit dans la table des sessions ; le game server valide la table des sessions et gère les données de personnage/jeu.

Dans les configurations plus importantes, un magasin en mémoire rapide comme Redis s'intercale : les jetons de session à courte durée de vie sont trop éphémères pour valoir une écriture sur disque persistant ; les garder en RAM est à la fois rapide et facile à nettoyer via une expiration automatique (TTL). Certaines architectures utilisent un canal RPC/message interne au lieu de partager directement les jetons : le serveur auth dit au game server « ce compte arrive avec ce jeton » via le réseau.

Quelle que soit la méthode, une règle ne change jamais : le canal entre les deux serveurs doit être interne et sécurisé. La validation du jeton ou le trafic RPC ne doivent pas être exposés à internet, et le client du joueur ne doit jamais atteindre ce canal.

Passer à une structure multi-realm

La vraie puissance, c'est de pouvoir placer plusieurs game servers derrière un seul login server. Le joueur se connecte, le serveur auth lui montre une liste de mondes, le joueur en choisit un, et le serveur auth émet le jeton qui le route vers le game server de ce monde.

  • Évolutivité horizontale : à mesure que la popularité augmente, vous ajoutez de nouveaux mondes (canaux), chacun étant son propre processus de game server.
  • Répartition de charge : le serveur auth peut masquer les mondes pleins ou orienter les nouveaux joueurs vers des canaux plus vides.
  • Maintenance facilitée : pour mettre à jour un monde, vous n'arrêtez que ce game server ; les joueurs continuent dans les autres mondes et le service de login ne tombe jamais.

Metin2, les émulateurs de type WoW et de nombreuses stacks MMO utilisent exactement ce modèle : une seule couche auth/compte, avec des cœurs de jeu séparés en canaux ou realms derrière elle.

Questions fréquentes

Vaut-il la peine de séparer le serveur auth pour un petit jeu ?

Un processus séparé dès le premier jour n'est pas obligatoire, mais séparer la logique d'emblée est très précieux. Si vous écrivez le code d'authentification comme un module indépendant de la boucle de jeu, le déplacer dans son propre processus quand le nombre de joueurs augmente devient un simple refactor ; s'il est entremêlé, cela devient une réécriture coûteuse.

Pourrais-je simplement envoyer le mot de passe à chaque paquet au lieu d'un jeton ?

Non. Transporter le mot de passe sur le réseau de façon répétée est à la fois un risque de sécurité et un calcul de hash coûteux à chaque vérification. Un jeton à usage unique et à courte durée de vie est à la fois sûr et peu coûteux à valider ; le mot de passe n'est traité qu'une fois, uniquement sur le serveur auth.

Si le serveur auth plante, les joueurs en jeu sont-ils expulsés ?

Non, pas dans une conception correcte. Le serveur auth n'intervient qu'à la connexion ; les joueurs dans le monde sont connectés au game server. Si le serveur auth tombe, seules les nouvelles connexions s'arrêtent, les sessions existantes ne sont pas affectées — c'est le plus grand avantage de résilience de cette séparation.

Vous voulez bâtir une architecture auth/login solide pour votre jeu ? Si vous avez besoin d'aide pour la séparation du login server, la gestion de session par jeton et l'évolutivité multi-monde, contactez-moi.

Bu kategorideki tüm yazılar →

Devamı için