Come si ottiene il bilanciamento del carico negli MMO?


26

Credo che sia un requisito comune degli MMO che l'elaborazione per un singolo frammento o regno possa essere eseguita su più server per facilitare il carico. Sono curioso di sapere come farlo, mantenendo un mondo coerente unificato in cui tutti i giocatori e tutti gli NPC possano interagire.

La mia domanda è: come si ottiene il bilanciamento del carico negli MMO?

Sono anche apprezzati eventuali link, libri o informazioni generali su come migliorare le mie conoscenze su questo argomento.

Risposte:


30

Cerca di mantenerlo il più semplice possibile e interfacce ben definite e documentate. Il mantenimento e il debug di un sistema complesso in produzione si trasforma facilmente in un inferno. Quindi, se esiste un approccio semplice e complesso, pensaci due volte prima di procedere con quello complesso.

Definizione dei servizi

Penso che il primo passo sia identificare i servizi e le loro dipendenze : Contenuto statico, Autenticazione, Chat locale, Canali di chat globali, Canali di chat regionali, Elenco amici, Gilde, Borsa / Inventario, Casa d'aste, Mappa globale, Mondo, ...

Quindi per ciascuno di questi servizi ha deciso se il client può parlare direttamente con loro. Ad esempio, è abbastanza facile lasciare che il client parli direttamente con i server responsabili dei canali di chat globali. I server del mondo non devono essere coinvolti nei messaggi di chat. La chat regionale può essere implementata allo stesso modo, ma i server del mondo devono comunicare ai server di chat quando i giocatori cambiano regione. Ancora una volta, non devono preoccuparsi dei messaggi.

Il terzo passo è pensare al bilanciamento del carico all'interno di un servizio . Ad esempio, i canali di chat globali e regionali possono essere suddivisi su più server in base al loro nome. È probabilmente una buona idea non codificare in modo rigido questa suddivisione nel client, ma fornire un servizio di ricerca.

Server mondiali

La parte più difficile di solito sono i server del mondo , quindi sto iniziando con un approccio semplice. Probabilmente è una buona idea lasciare che il client parli direttamente con il server responsabile della regione in cui si trova. Pertanto, al momento del login o della regione che attraversa il client, deve essere detto a quale server connettersi.

L'approccio semplice è quello di dividere il mondo in regioni indipendenti . Con regioni indipendenti intendo che un giocatore non può guardare da una parte all'altra e i mostri non possono attraversare le parti. Quelle regioni sono diverse da quelle che il giocatore vede in base al paesaggio e alla storia del mondo esterno. Di solito la maggior parte dei mostri si trova nei sotterranei e i giocatori tendono ad accettare che devono attraversare un gateway per entrare in un sotterraneo. Soprattutto se quei sotterranei vengono istanziati in base al gruppo di giocatori. Altri esempi nel mondo esterno sono i diversi continenti e valli racchiusi da alte montagne.

Un approccio al mondo continuo diventa complesso molto rapidamente, quindi ha senso pianificarlo bene: di quali informazioni ha bisogno il cliente? Quali informazioni devono condividere i server? Il giocatore interagirà principalmente solo con gli oggetti (inclusi mostri e NPC) nella stessa regione. Puoi imbrogliare posizionando gli oggetti al di fuori dell'intervallo di clic dal bordo della zona. Ciò significa che il cliente è principalmente interessato a leggere solo informazioni per le zone vicine. In questi casi i server di zona non devono coordinare nulla tranne che per il controllo delle autorizzazioni che il giocatore è abbastanza vicino per connettersi a una zona vicina.

Questo lascia solo un numero molto piccolo di casi difficili in cui oggetti o azioni devono attraversare un bordo del server. Il che è positivo perché quei casi come frecce e incantesimi sono fondamentali per le prestazioni. Potrebbe essere una buona idea dividere il combattimento in attacco e difesa. Quindi il server di un incantatore definirà i parametri di attacco inclusa la posizione dell'incantatore. Il server del difensore riceverà il messaggio sull'attacco e calcolerà l'impatto. Il server dell'attaccante non ha bisogno di conoscere l'impatto; il cliente lo imparerà usando la sua connessione di sola lettura.

A seconda della complessità del modello del tuo lettore, potrebbero essere necessari alcuni secondi per trasferirlo su un altro server (Second Life ha un grosso problema con questo). Il problema può essere mitigato preparando il trasferimento in anticipo quando il giocatore si avvicina a un bordo virtuale. In modo che la maggior parte dei dati del giocatore sia già memorizzata nella cache sul server di destinazione quando si verifica la consegna effettiva.

Sommario

Dividi il problema definendo diversi servizi che possono essere suddivisi tra server con piccole dipendenze. Come passo successivo, guarda come fare il bilanciamento del carico all'interno dei servizi critici. Delegare il lavoro di bilanciamento al client istruendolo a connettersi direttamente ai server pertinenti (ovviamente i server devono verificare le autorizzazioni). Mantenerlo il più semplice possibile, documentare bene le responsabilità dei vari servizi e server, fornire l'opzione per abilitare l'output di debug.

PS: alcune di queste tecniche possono essere utilizzate per migliorare l'affidabilità. E dovresti tenerlo a mente perché l'uso di molti server implica un rischio molto più elevato di rottura delle cose; non solo nel software ma anche a livello hardware.


Ma davvero, come si fa a comunicare tra processi? che tipo di IPC dovrebbe essere usato?
majidarif,

10

Generalmente il mondo è diviso in un numero di regioni più piccole. Ognuna di queste regioni è di solito un processo server indipendente (i server mondiali di WoW o i nodi Sol di Eva) e può essere eseguito su un numero qualsiasi di macchine. In alcuni giochi ci sono porte esplicite tra le mappe (Eve, STO, Guild Wars) mentre altri cercano di mascherare di più (WAR, Free Realms). Coloro che optano per un approccio più uniforme generalmente rileveranno quando ci si avvicina al confine tra due server e i due processi negoziano un handoff. Il posto migliore per cercare probabilmente una descrizione di ciò è come le torri cellulari eseguono i handoff di telefoni mobili. Se il carico di una singola mappa (Jita, Ironforge, Earth Space Dock) aumenta davvero, a volte puoi scaricare singole funzioni su altri server (AI, alcune parti della gestione dei giocatori) ma questo deve essere integrato dall'inizio o richiederebbe un serio adattamento. È quasi sempre più conveniente acquistare solo hardware migliore da dedicare a quelle poche mappe.


9

Credo che sia un requisito comune degli MMO che l'elaborazione per un singolo frammento o regno possa essere eseguita su più server per facilitare il carico. Sono curioso di sapere come farlo, mantenendo un mondo coerente unificato in cui tutti i giocatori e tutti gli NPC possano interagire.

Probabilmente non è così comune come pensi; almeno, non se stai pensando che un mondo senza soluzione di continuità è gestito da più server contemporaneamente.

Senza contare i frammenti totalmente separati, ci sono 2 direzioni in cui puoi dividere un gioco online, che potrebbe essere considerato "orizzontale" e "verticale":

  • Dividi il gioco in molte aree geografiche separate. Tutte le funzionalità di una determinata area geografica sono gestite da un server e non esiste alcuna interazione reale tra di loro. (Si noti che non esiste necessariamente solo 1 zona per server: un server può gestire più zone contemporaneamente e le zone possono forse essere trasferite tra server per gestire il cambiamento del carico.)
  • Dividi il gioco in diversi tipi di servizi, ad es. login / autorizzazione, regole di gioco e fisica, chat + aste, persistenza, ecc. Ciascuno di questi servizi può essere gestito da un server diverso. La risposta di nhnb ha elencato altri potenziali servizi in cui uno sviluppatore può partizionare il proprio gioco.

Ovviamente questi approcci sono ortogonali e puoi combinare i due. In effetti è quasi obbligatorio avere un server di database separato, molto comune per trasferire login / auth su una macchina separata dal gameplay e sempre più comune per coltivare anche chat e altre comunicazioni non critiche, indipendentemente dal mondo di gioco è diviso.

Ma nel complesso, quando c'è il partizionamento geografico, la maggior parte dei giochi evita di farti interagire attraverso quei confini, perché è difficile fare bene. Invece, ricorrono ad altri modi per far sembrare che tu sia ancora nello stesso frammento e sullo stesso server, quando in realtà non lo sei. per esempio. - caricamento di schermate o altre animazioni che nascondono una modifica del server durante la transizione da una zona all'altra o da un continente all'altro. - separare le istanze di dungeon o raid che sono isolate da tutti gli altri. Questi sono come un frammento all'interno di un frammento e possono essere facilmente eseguiti su un server separato, aiutando il bilanciamento del carico.

Non posso parlare con autorità su WoW ma immagino che stiano facendo quasi tutto quanto sopra: istanza, aree geografiche separate che non possono interagire unite da portali di qualche tipo, back-end separati e server di autenticazione. Ho sentito che i regni WoW hanno qualcosa tra 1000 e 10000 giocatori online in un dato regno contemporaneamente, che è facilmente gestibile con gli schemi di cui sopra.

Ma supponiamo che tu abbia un unico enorme mondo e che sia necessario consentire ai giocatori un server per interagire con i giocatori su un server adiacente. In teoria questo è facile da fare: in primo luogo, i server devono cooperare per condividere i dettagli degli oggetti lungo i bordi (quindi un oggetto su un server può avere una rappresentazione proxy su un altro), quindi cambiare semplicemente tutta la logica in passaggio di messaggi, con i messaggi vengono instradati da un proxy indietro alla fonte autorevole dove necessario. I messaggi possono essere passati tra server o all'interno di un server in modo abbastanza trasparente, quindi un approccio si adatta a tutti i sistemi.

Il problema qui è che la logica precedentemente semplice può diventare molto complessa quando tradotta in messaggi - ad es. uno scambio di 2 giocatori che può avvenire in modo sicuro e atomico quando entrambi i giocatori si trovano su un server diventa un processo più lungo quando i messaggi devono essere inviati avanti e indietro, riverificati su ogni invio e misure di sicurezza messe in atto per garantire che un giocatore non possa sfruttare l'altro cambiando il commercio mentre un messaggio viaggia. Non puoi nemmeno supporre che l'altro giocatore esista ancora quando arriva il messaggio (poiché potrebbero morire, disconnettersi, ecc.), Quindi il codice diventa molto complesso. E questo si applica a quasi tutti i sistemi in cui 2 o più entità possono interagire o cooperare: commercio, combattimento, raggruppamento, aste, condivisione di bottino, addestramento, ecc.

Questi problemi non sono insormontabili ma per la maggior parte dei giochi sono troppo difficili da provare quando puoi condividere il carico con gli altri mezzi e mantenere tutta la logica di gioco su un server. Quindi quasi tutti i giochi attuali seguono questa strada.


3

Esistono molti metodi di bilanciamento del carico di un server MMO, poiché esiste una gamma abbastanza ampia di dati da elaborare. Preferisco il metodo dell'albero del raccoglitore di processo.

Un server globale passa le connessioni utente a un raccoglitore di processo in grado di gestire più utenti contemporaneamente. i bin del processo eseguono tutta l'elaborazione complessa e rispondono solo al server globale con dati rilevanti a livello globale come chat globale e posizionamento. Questo metodo equilibra molto meglio dei server regionali, poiché le regioni possono variare notevolmente nella popolazione, mentre l'elaborazione complessiva dell'utente è abbastanza varia che dovrebbe naturalmente bilanciarsi per la maggior parte.

Basta eseguire un bilanciamento del carico di base tramite il server globale, quindi quando un raccoglitore di processo raggiunge un determinato utilizzo di memoria / CPU, si avvia un nuovo server del raccoglitore di processo.


Come si condividono i dati condivisi tra i bin di processo, ad esempio una lotta tra due utenti su bin di processo diversi. Come garantite l'ordine degli eventi? In modo che un giocatore ucciso non possa più effettuare alcun attacco, anche se il cestino che lo uccide è più lento di quello che fa l'attacco. Esiste il rischio che l'overhead del dispacciamento arrivi in ​​alto sul server globale? Il modello proxy per le connessioni utente potrebbe entrare nei limiti del sistema operativo nello stack di rete.
Hendrik Brummermann,

Questo modello funziona abbastanza bene nei sistemi di informazione in cui la maggior parte delle transazioni sono isolate. Voglio dire, di solito non funzionano sugli stessi dati e in rari casi viene utilizzato il blocco o il rollback. Ma nei giochi in cui i combattimenti includono più giocatori e / o creature e l'impatto degli attacchi è influenzato dagli attributi sia dell'attaccante che del difensore, questo approccio può essere difficile.
Hendrik Brummermann,

Puoi procedere in modo semplice e considerare le interazioni multiutente come rilevanti a livello globale, oppure puoi creare un metodo semplice per consentire ai contenitori di processi di conoscersi e comunicare tra loro. Ciascuno scomparto del processo dovrebbe essere in grado di gestire circa diecimila utenti contemporaneamente, quindi la comunicazione dello stato tra gli utenti non dovrebbe essere un grosso problema. Il metodo della regione è un po 'più semplice, ma non altrettanto equilibrato, e può essere facilmente bloccato se troppi utenti entrano nella stessa regione. In un MMORPG con una vasta base di utenti, il bilanciamento uniforme del carico è molto importante.
Stephen Belanger,

Mi piacerebbe sapere "un metodo semplice" per 2 contenitori di processo per poter negoziare un sistema come il combattimento. Il problema non sono le comunicazioni di basso livello, ma i tipici algoritmi di gioco diventano molto complicati con i partecipanti distribuiti.
Kylotan,

Nella mia implementazione, il mio server globale mantiene un elenco di tutti i client connessi e tiene traccia del contenitore dei processi a cui sono connessi. Se un cestino del processo deve accedere a un altro utente, controlla innanzitutto il proprio elenco utenti. Se ciò non riesce, controlla l'elenco globale e identifica a quale bin di processo si connette l'altro utente. I bin del processo si connettono quindi direttamente per condividere gli stati dell'utente mentre esegue l'elaborazione unificata.
Stephen Belanger,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.