C'è un modo per rendere un mondo dinamico come un MMORPG scalabile orizzontalmente?


11

Immagina un mondo aperto di oltre 500 giocatori con dati che cambiano in soli 20 aggiornamenti / giocatore / secondo. L'ultima volta che ho lavorato in un MMORPG simile, ha usato SQL, quindi, per ovvio, non è stato possibile interrogare continuamente il DB. Invece, ha caricato tutti i lettori dal DB in memoria come oggetti C ++ e li ha usati. Cioè, si è ridimensionato verticalmente. Sarebbe possibile invece rendere quel server scalabile orizzontalmente? Esiste un database progettato per supportare contemporaneamente tale quantità di aggiornamenti?


Perché vuoi aggiornare il lettore nel database 20 volte / secondo?
Balon,

@Balon è lì che sono confuso. Se non lo aggiorno nel database, solo nella memoria, allora avrò stati diversi tra macchine diverse. Ma immagino che gli aggiornamenti di DB abbiano un enorme sovraccarico, quindi non funzionerà davvero per quella quantità di aggiornamenti?
MaiaVictor

2
Se pensi davvero che macchine diverse (o persino processi) necessitino di aggiornamenti a 20Hz su centinaia di oggetti, allora bypassa completamente il database e usa direttamente un sistema di messaggistica. Ma quello che davvero, davvero pensi di volere non è quello che vuoi davvero. Quello che vuoi è avere un ambito sano di chi ha bisogno di sapere cosa e quindi avere un modo per trasportare ordinatamente oggetti tra gli ambiti sopra a quello. Dovresti rispondere alla domanda sul perché hai bisogno di aggiornamenti a 20Hz tra macchine diverse per ottenere grandi risposte, qualcuno potrebbe pensare a un nuovo modo di vedere il problema.
Patrick Hughes,

@PatrickHughes Non so di cosa ho bisogno, sto solo spiegando come funziona il gioco. I personaggi muovono 2 ~ 3 tessere / secondo. Un cacciatore può essere circondato da alcuni mostri, quindi almeno 10 tessere / giocatore / secondo. Poi ci sono oggetti in decomposizione sul pavimento, nello zaino del giocatore. Ci sono attacchi che si muovono nella direzione del giocatore, ci sono attacchi che si muovono nella direzione del mostro. C'è il decadimento della salute, il mana usato, i timer che infliggono danni da veleno al giocatore. Quindi, le cose cambiano molto velocemente. Questo è il design del gioco. In che modo tale design può essere ridimensionato verticalmente?
MaiaVictor

1
L'ho visto su HackerNews poco tempo fa: paralleluniverse.co Stanno lavorando su un database che fa tutto il materiale spaziale di segmentazione / distribuzione per te. Immagino che sotto il cofano stiano facendo tutte le cose nelle risposte qui sotto.
rimorchiatori

Risposte:


17

Caso di prova di 500 giocatori tutti in comunicazione, ovvero 250.000 flussi di informazioni che volano intorno a 20Hz. La larghezza di banda interna per questo sarebbe, assumendo 100 byte per ogni messaggio, circa 500 MB / sec. Sembra ambizioso. Soprattutto tra i processi.

Se segreghi i giocatori in gruppi di 100, questo si abbassa a 20 MB / sec e così via. Ecco perché gli MMO hanno zone e in quelle zone piccole bolle di influenza, e così via verso il basso fino a quando la larghezza di banda diventa ragionevole.

Il problema originale può essere affermato che se hai 10 persone che condividono tutte le informazioni in tempo reale, ma ne vuoi 500 tutte , è una crescita esponenziale dei collegamenti di comunicazione e come possiamo aggirarli . Temo che non abbia mai sentito parlare di un proiettile magico che possa magicamente far scomparire la progressione geometrica.

Non utilizzare un database per comunicare, ecco a cosa serve la messaggistica. Usa il database per imporre transazioni e archiviare informazioni che non vuoi che i giocatori perdano. La maggior parte degli MMO con cui ho familiarità aggiorna il database con informazioni dinamiche sui giocatori ogni 1-10 minuti, o in punti utili come le transizioni di zona o inserendo zone "sicure" nel progetto.

Potrebbe essere necessario ridisegnare la necessità del gioco per ogni giocatore, non importa quanto lontano, di avere aggiornamenti in tempo reale del contenuto dello zaino di ogni altro giocatore.

Cambia anche il modello di aggiornamento da 20Hz a una velocità in base alla distanza, qualcuno a 1 miglio di distanza non ha bisogno di sapere che hai spostato 1 piede esattamente a 230,6 secondi, quindi un altro piede a 231,4 secondi, possono farti muovere di 15 piedi ogni 10 secondi.


Risposta fantastica e istruttiva, grazie. Ma potrei aggiungere che mentre il mondo cambia a un ritmo molto veloce, un giocatore può vedere solo altri giocatori immediatamente accanto a lui. Non lo vedo come geometrico: 500 giocatori inviano informazioni al server; il server invia periodicamente informazioni a quei 500 giocatori. È lineare, come vedo. Ma il punto principale è sul quarto paragrafo: se uso solo il database per l'archiviazione, quindi sto caricando i dati in memoria. Se sto caricando i dati nella memoria di una macchina, sto creando una versione desincronizzata del mondo. Questo è quello che non capisco.
MaiaVictor

Per 1 client: 1 msg in uscita + 1 msg in = 2. Per 2 client: 2 msg in uscita, 2 msg in = 4. Per 3 client: 3 msg in uscita, 3 msg in = 9. E così va. È così: invia un messaggio di stato, il server invia il risultato a me e agli altri 2 client (1 in, 3 out) e 3 client tutti che lo fanno (1 in 9 out). Sebbene appaia lineare per un solo client su 3, puoi moltiplicarlo per tutti i client per il throughput totale del sistema. Per quanto riguarda la desincronizzazione, anche i processi sulla stessa scatola fisica non sono sincronizzati fino a quando non viene creato e inviato il messaggio di stato, è solo una questione di dove si svuota la pipe, RAM locale o rete.
Patrick Hughes,

5

Utilizza il filtro dell'area di interesse. Se un mondo è suddiviso in 3 server e l'area sul server 1 non si trova vicino all'area del server 3, non c'è motivo per loro di condividere informazioni sulle entità.

Allo stesso modo, su un singolo server, inviare solo le informazioni rilevanti ai client. Se il giocatore A si trova sull'estremità opposta della mappa rispetto al giocatore B, non c'è motivo di inviare aggiornamenti da B ad A o viceversa.

Quando si hanno più server in un mondo continuo, si avranno entità vicine a un bordo sul server 2 che sono vicine alle entità sul server 1. È possibile inviare gli aggiornamenti dal server "autorevole" per un'entità all'altro server (se appropriato) e allo stesso modo inoltrare qualsiasi messaggio al server autorevole come appropriato.

Sì, in questo caso, un server sarà leggermente obsoleto per determinate entità. Non provare a risolverlo. Basta occuparsene. Supponiamo che le entità potrebbero essere un po 'obsolete. Esegui qualsiasi logica che richieda informazioni aggiornate solo sul server proprietario autorevole delle entità. Quando un'entità influisce su un'altra, invia un messaggio e presumi che possa richiedere più tick di logica di gioco prima che venga elaborata e la tua vista venga aggiornata.

Questo design semplifica inoltre il threading di un singolo server. Nessuna entità dovrebbe modificarne direttamente un'altra, inviare solo messaggi e le cache del proxy locale per server / per thread dovrebbero essere considerate non aggiornate.

Ad esempio, se l'entità A attacca l'entità B, non controllare la vita di B e quindi inviare un messaggio di morte se colpisce 0. Basta inviare un messaggio "danneggiato", lasciare che il server autorevole per B lo gestisca e quindi gestire qualsiasi Messaggio "entità morto" inviato successivamente dal server B se l'entità A se ne preoccupa.

Lo stesso vale per qualsiasi applicazione non di giochi di grandi dimensioni e scalabile. Un database centrale non è una magica tecnologia di condivisione istantanea. Due server devono comunicare con i messaggi, in modo asincrono, in batch, al fine di mantenere un throughput elevato. Da qui la popolarità di tecnologie come AMPQ e simili. I database servono per l'archiviazione e supportano la sincronizzazione per necessità, consentendo loro di essere utilizzati per le comunicazioni, non perché sono essi stessi pensati per la sincronizzazione o la comunicazione.


Grazie, questo ha posto fine alla maggior parte dei miei dubbi rimanenti. Inoltre mi hai dato l'idea di separare i server dai giocatori, non dalle aree: sembrerebbe più fluido. Ogni server si occupa di x giocatori. Mi piace molto questo! È usato? E inoltre, c'è solo un'altra cosa. Come ho chiesto sopra, ho appena imparato a conoscere un nuovo database NoSQL, Couchbase. Dovrebbe essere proprio come CouchDB, tranne che con velocità di scrittura / lettura molto elevate: fino a 200k aggiornamenti al secondo! Forse questo potrebbe effettivamente funzionare come un "modello di mondo condiviso in tempo reale", o non ancora?
MaiaVictor

Non ho idea se questa tecnica venga utilizzata in natura oltre al solito "partizionamento" approssimativo dei server. Farlo dai giocatori e dall'area geografica significa che ogni server potrebbe dover essere a conoscenza di un numero molto elevato di entità in una vasta gamma di aree, aumentando il carico del server e aumentando notevolmente la comunicazione tra server. Farlo per area significa che il tuo server potrebbe essere sovraccaricato in aree affollate (anche se puoi dividere dinamicamente e unire le aree in quel caso), ma significa che ogni server ha un set più piccolo di entità e geometria non player rilevanti per tenere traccia di .
Sean Middleditch il

@Dokkat: potrebbe essere possibile avere una sorta di "aree morbide" in cui ogni server gestisce principalmente i giocatori in una particolare parte del mondo di gioco, ma li fa passare in modo trasparente al giocatore su un altro server se si allontanano troppo da la regione del loro server originale. Dovresti solo assicurarti che la consegna sia abbastanza regolare che i giocatori non se ne accorgano davvero. Potresti anche provare ad usare alcune fantasiose tecniche adattive per mantenere i gruppi di giocatori che interagiscono sullo stesso server, anche se si trovano solo al limite di una regione.
Ilmari Karonen,


2

Non pensare al database come a un qualche tipo di modello di mondo condiviso in tempo reale che memorizza tutto su tutto in ogni momento - come hai notato, che probabilmente non può funzionare.

Invece, tratta il database più come un file di salvataggio aggiornato automaticamente: aggiorni il database solo occasionalmente, ad esempio quando i giocatori accedono o si disconnettono o si spostano da una zona all'altra o ogni volta che accade qualcosa di importante che non vuoi essere perso in caso di crash del server.

L'attuale stato mondiale in tempo reale dovrebbe essere mantenuto dai server di gioco, in memoria, proprio come nell'esempio originale. Ora, il trucco per il ridimensionamento orizzontale è che non tutti i server devono sapere tutto in ogni momento . Per esempio, se il giocatore A sta giocando nella zona A sul server A, il server B in esecuzione zona B di solito non ha bisogno di sapere che cosa il giocatore A ha nello zaino - e, se fa bisogno di sapere che per qualche motivo (ad esempio, poiché il giocatore B nella zona B lancia una sorta di incantesimo di spionaggio remoto su A) può semplicemente chiedere quelle informazioni all'altro server .

Ciò richiede che tu assegni chiare responsabilità ai server, in modo che quando il server B vuole conoscere lo zaino del giocatore A, sappia quale server ha le informazioni autorevoli al riguardo. Probabilmente vorrai anche includere un qualche tipo di meccanismo di abbonamento di aggiornamento, in modo che ad esempio il server B possa semplicemente dire al server A " Ho qualcuno che spia il giocatore A, tienimi aggiornato su tutto ciò che fanno fino a quando non ti dirò diversamente. " Probabilmente desidera anche includere un qualche tipo di sistema di trasmissione globale per importanti eventi globali che i giocatori potrebbero aver bisogno di conoscere, indipendentemente da dove si trovino; ovviamente, tali eventi dovrebbero anche essere registrati nel database, ma averli attivamente trasmessi a tutti i server significa che i server non dovranno continuare a eseguire il polling del database per gli aggiornamenti.


Risposta fantastica! Questo era esattamente quello che stavo chiedendo, grazie. Quindi forse la chiave è dividere il server in aree, mantenendo la logica in memoria. Potrei aggiungere, però: ho appena imparato a conoscere un nuovo database NoSQL, Couchbase. Dovrebbe essere proprio come CouchDB, tranne che con velocità di scrittura / lettura molto elevate: fino a 200k aggiornamenti al secondo! Forse questo potrebbe effettivamente funzionare come un "modello di mondo condiviso in tempo reale", o non ancora?
MaiaVictor

@Dokkat no, non lo farà. Couchbase non è magico.
Philipp

2

Altre risposte hanno fatto un buon lavoro nel sottolineare come usare un database e non usare un database per la comunicazione. Un altro aspetto che potresti esaminare è quello di classificare i tuoi aggiornamenti in base al modo in cui le informazioni devono essere comunicate ad altre entità. Invece di comunicare con l'ambito ai server, è possibile distribuire la messaggistica e utilizzare i meccanismi pubsub per comunicare gli aggiornamenti tra le entità. Ad esempio, potresti trattare la posizione in modo diverso in base a chi ti è vicino:

  • La posizione precisa e in tempo reale potrebbe essere utile nel raggio R
  • Aggiornamenti della posizione meno precisi e meno frequenti potrebbero essere utili nel raggio 2 * R
  • Nessuna informazione sulla posizione potrebbe essere necessaria oltre il raggio 2 * R

È possibile comunicare le informazioni sulla posizione di un'entità eseguendo periodicamente la ricerca di entità entro il raggio 2 * R (o alcuni multipli di ciò in base alla velocità di aggiornamento e alla velocità massima di un'entità) e sottoscrivendo l'entità al feed di posizione preciso o impreciso dell'altra entità.

Potresti avere strategie diverse per diversi tipi di informazioni, raggruppare cose comuni nelle stesse code di messaggi o avere code diverse per i messaggi che devono andare a entità diverse (o semplicemente inviarli al più ampio set di entità e avere messaggi scartati se non sono utili).

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.