De eerste echte stap naar een schaalbare online game-architectuur is meestal deze: het scheiden van de game auth server van de server die de spelwereld zelf draait. Wanneer één proces zowel de wachtwoorden van inkomende spelers probeert te verifiëren als tegelijkertijd de beweging, het gevecht en de inventaris van duizenden personages verwerkt, haalt de kleinste verkeerspiek de hele wereld onderuit. Het antwoord is om authenticatie naar een aparte login server te verplaatsen en de spellogica naar een of meer game servers.
Wat de auth server precies doet
De auth server (login server) is de poortwachter die de identiteit van een speler verifieert en hem het recht geeft een spelwereld binnen te gaan. In een typische flow zijn zijn taken:
- Authenticatie: hij controleert de gebruikersnaam en het wachtwoord (in gehashte vorm) tegen de database.
- Accountstatus: hij handhaaft bans, betaling/abonnement, leeftijdsgrenzen en IP-/hardware-blacklists.
- Serverlijst: hij toont de speler welke werelden (realms/channels) open zijn en hoe vol ze zitten.
- Uitgifte van de sessietoken: bij een geslaagde login genereert hij een eenmalige, kortlevende
session tokenen geeft die door aan de game server.
Het cruciale punt: de auth server stapt eruit zodra de login klaar is. Zodra de speler in de wereld is, praat hij niet meer met de auth server; al het real-time verkeer gaat naar de game server.
Waarom je ze scheidt: de problemen van één server
Login en spellogica in hetzelfde proces houden lijkt in het begin eenvoudig, maar brengt enkele fundamentele problemen met zich mee:
- Zeer verschillende belastingsprofielen: login is kort maar CPU-intensief (verificatie van de wachtwoordhash) en database-gebonden; de game loop heeft constant netwerkverkeer met lage latentie nodig. Beide in dezelfde thread-pool stoppen betekent dat een avondlijke loginpiek lag veroorzaakt voor iedereen die al speelt.
- Beveiligingsoppervlak: wachtwoorden en accountgegevens zijn de meest gevoelige bezittingen. Ze in een apart proces houden met strengere beveiligingsregels, geïsoleerd van de spellogica, verkleint het aanvalsoppervlak.
- Single point of failure: als een game server crasht, is alleen die wereld getroffen; maar als alles één proces is, sluit één crash alle spelers buiten, ook degenen die alleen wilden inloggen.
- Schaalbaarheid: één auth server kan tientallen game servers erachter voeden. Als het aantal spelers groeit, voeg je game servers toe, zonder de login-infrastructuur te hoeven dupliceren.
Token-gebaseerde handshake
Veilige communicatie tussen login- en game server verloopt via een sessietoken. De klassieke flow: de speler logt in op de auth server, de auth server genereert een kortlevende token en geeft die aan zowel de speler als (via een gedeelde DB of het interne netwerk) de game server, de speler verbindt met de game server met die token, en de game server valideert hem.
// Auth server: een token uitgeven bij geslaagde login
Token issueSession(uint32_t accountId) {
Token t;
t.value = randomBytes(32); // onvoorspelbaar
t.account = accountId;
t.expires = now() + seconds(30); // korte levensduur
t.used = false;
db.storeSession(t); // naar gedeelde tabel schrijven
return t;
}
// Game server: de token valideren wanneer de speler verbindt
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; // verlopen
db.markUsed(token); // eenmalig gebruik
return true;
}
De belangrijkste eigenschappen: de token moet onvoorspelbaar zijn (cryptografisch willekeurig), kortlevend (seconden) en eenmalig. Zo blijft, zelfs als hij wordt onderschept, het venster minuscuul. Het wachtwoord bereikt de game server nooit; de game server bespreekt met niemand wachtwoorden, hij valideert alleen tokens.
Database en gedeelde state
Hoe communiceren de twee servers? De meest gebruikelijke aanpak is een gedeelde database (meestal MySQL): accounts, sessies en personagegegevens staan in centrale tabellen. De auth server leest de accounttabel en schrijft naar de sessietabel; de game server valideert de sessietabel en beheert de personage-/spelgegevens.
In grotere opstellingen komt er een snelle in-memory store als Redis tussen: kortlevende sessietokens zijn te vluchtig om naar persistente schijf te schrijven; ze in RAM houden is zowel snel als makkelijk op te ruimen via automatische vervaltijd (TTL). Sommige architecturen gebruiken een intern RPC/message-kanaal in plaats van tokens direct te delen: de auth server vertelt de game server "dit account komt eraan met deze token" over het netwerk.
Welke methode ook, één regel verandert nooit: het kanaal tussen de twee servers moet intern en beveiligd zijn. Tokenvalidatie of RPC-verkeer mag niet aan het internet blootgesteld zijn, en de client van de speler mag dat kanaal nooit bereiken.
Overstappen naar een multi-realm structuur
De echte kracht is dat je meerdere game servers achter één login server kunt plaatsen. De speler logt in, de auth server toont hem een werelden-lijst, de speler kiest er een, en de auth server geeft de token uit die hem naar de game server van die wereld stuurt.
- Horizontaal schalen: naarmate de populariteit groeit, voeg je nieuwe werelden (channels) toe, elk een eigen game server-proces.
- Load balancing: de auth server kan volle werelden verbergen of nieuwe spelers naar legere channels sturen.
- Eenvoudiger onderhoud: om een wereld bij te werken zet je alleen die ene game server uit; spelers blijven in andere werelden spelen en de login-service gaat nooit plat.
Metin2, WoW-achtige emulators en veel MMO-stacks gebruiken precies dit model: één auth-/accountlaag, met spelcores erachter opgesplitst als channels of realms.
Veelgestelde vragen
Is het de moeite waard om de auth server te scheiden voor een kleine game?
Een apart proces vanaf dag één is niet verplicht, maar de logica vooraf scheiden is zeer waardevol. Als je de authenticatiecode schrijft als een module die los staat van de game loop, is het verplaatsen naar een eigen proces bij groeiend spelersaantal een eenvoudige refactor; als het verweven is, wordt het een dure herschrijving.
Kan ik niet gewoon het wachtwoord bij elk pakket sturen in plaats van een token?
Nee. Het wachtwoord herhaaldelijk over het netwerk vervoeren is zowel een beveiligingsrisico als een dure hash-berekening bij elke controle. Een kortlevende, eenmalige token is zowel veilig als goedkoop te valideren; het wachtwoord wordt slechts één keer verwerkt, alleen op de auth server.
Worden spelers in de game eruit gegooid als de auth server crasht?
Nee, niet in een correct ontwerp. De auth server is alleen bij de login betrokken; spelers in de wereld zijn verbonden met de game server. Als de auth server uitvalt, stoppen alleen nieuwe logins, bestaande sessies blijven onaangetast — dat is het grootste robuustheidsvoordeel van de scheiding.
Wil je een solide auth-/login-architectuur bouwen voor je game? Heb je hulp nodig bij login server-scheiding, token-gebaseerd sessiebeheer en multi-wereld schalen, neem dan contact met me op.