¿Hay alguna manera de hacer un mundo dinámico como un MMORPG escalable horizontalmente?

11

Imagine un mundo abierto de más de 500 jugadores con datos que cambian tan rápido como 20 actualizaciones / jugador / segundo. La última vez que trabajé en un MMORPG similar, usó SQL, por lo que obviamente no podía consultar la base de datos todo el tiempo. En cambio, cargó a todos los jugadores desde la base de datos a la memoria como objetos C ++ y los usó. Es decir, se escaló verticalmente. ¿Sería posible hacer que ese servidor sea escalable horizontalmente? ¿Existe una base de datos diseñada para admitir esa cantidad de actualizaciones al mismo tiempo?

MaiaVictor
fuente
¿Por qué quieres actualizar el reproductor en la base de datos 20 veces / segundo?
Balon
@Balon, ahí es donde estoy confundido. Si no lo actualizo en la base de datos, solo en la memoria, tendré diferentes estados entre diferentes máquinas. Pero supongo que las actualizaciones de DB tienen una gran sobrecarga, por lo que realmente no funcionará para esa cantidad de actualizaciones.
MaiaVictor
2
Si realmente, realmente piensa que diferentes máquinas (o incluso procesos) necesitan actualizaciones de 20Hz en cientos de objetos, entonces omita completamente la base de datos y use un sistema de mensajería directamente. Pero lo que realmente crees que quieres no es lo que realmente quieres. Lo que desea es tener un alcance sensato de quién necesita saber qué y luego tener una forma de transportar objetos perfectamente entre ámbitos además de eso. Debería responder a la pregunta de por qué necesita actualizaciones de 20Hz entre diferentes máquinas para obtener excelentes respuestas, alguien podría pensar en una nueva forma de ver el problema.
Patrick Hughes
@PatrickHughes No sé lo que necesito, solo estoy explicando cómo funciona el juego. Los personajes se mueven 2 ~ 3 fichas / segundo. Un jugador que caza puede estar rodeado de unos pocos monstruos, por lo que al menos 10 fichas / jugador / segundo. Luego hay elementos que se descomponen en el piso, en la mochila del jugador. Hay ataques que se mueven en dirección al jugador, hay ataques que se mueven en dirección al monstruo. Existe la decadencia de la salud, el maná que se usa, los temporizadores que aplican daño de veneno al jugador. Entonces, las cosas cambian muy rápido. Este es el diseño del juego. ¿Cómo podría tal diseño escalarse verticalmente?
MaiaVictor
1
Hace un tiempo vi esto en HackerNews: paralleluniverse.co Están trabajando en una base de datos que hace todo lo relacionado con la segmentación / distribución espacial. Supongo que debajo del capó, están haciendo todas las cosas en las respuestas a continuación.
tirones

Respuestas:

17

Caso de prueba de 500 jugadores que se comunican, eso es 250,000 flujos de información que vuelan a 20Hz. El ancho de banda interno para eso sería, suponiendo 100 bytes por mensaje, aproximadamente 500 MB / seg. Suena ambicioso Especialmente entre procesos.

Si segrega a los jugadores a grupos de 100, eso se reduce a 20 MB / seg, y así sucesivamente. Es por eso que los MMO tienen zonas, y en esas zonas pequeñas burbujas de influencia, y así sucesivamente hacia abajo hasta que el ancho de banda sea razonable.

El problema original se puede afirmar que si tienes 10 personas que comparten información en tiempo real, pero quieres que todas compartan 500 , eso es un crecimiento exponencial de los enlaces de comunicación y cómo podemos evitarlo . Me temo que no he oído hablar de una bala mágica que mágicamente pueda hacer que la progresión geométrica desaparezca.

No use una base de datos para comunicarse, para eso está la mensajería. Use la base de datos para imponer transacciones y almacenar información que no desea que los jugadores pierdan. La mayoría de los MMO con los que estoy familiarizado solo actualizan la base de datos con información dinámica del jugador cada 1-10 minutos, o en puntos útiles como transiciones de zona o ingresando zonas "seguras" en el diseño.

Es posible que tengas que rediseñar la necesidad del juego para cada jugador, sin importar qué tan lejos esté, para tener actualizaciones en tiempo real del contenido de la mochila de cada otro jugador.

También cambie el patrón de actualización de 20Hz a una velocidad basada en la distancia, alguien a 1 milla de distancia no necesita saber que movió 1 pie exactamente a 230.6 segundos, luego otro pie a 231.4 segundos, pueden lidiar con usted moviéndose 15 pies cada 10 segundos.

Patrick Hughes
fuente
Impresionante e informativa respuesta, gracias. Pero podría agregar que si bien el mundo cambia a un ritmo muy rápido, un jugador solo puede ver a otros jugadores inmediatamente a su lado. No lo veo como geométrico: 500 jugadores envían información al servidor; el servidor envía periódicamente información a esos 500 jugadores. Es lineal, como veo. Pero el punto principal está en el cuarto párrafo: si solo uso la base de datos para el almacenamiento, entonces estoy cargando datos en la memoria. Si estoy cargando datos a la memoria en una máquina, estoy creando una versión desincronizada del mundo. Eso es lo que no entiendo.
MaiaVictor
Para 1 cliente: 1 mensaje de salida + 1 mensaje de entrada = 2. Para 2 clientes: 2 mensaje de salida, 2 mensaje de entrada = 4. Para 3 clientes: 3 mensaje de salida, 3 mensaje de entrada = 9. Y así sigue. Es así: envía un mensaje de estado, el servidor me envía el resultado a mí y a los otros 2 clientes (1 entrada, 3 salidas) y 3 clientes lo hacen (1 entrada 9 salidas). Si bien parece lineal para un solo cliente de los 3, puede multiplicar eso por todos los clientes para obtener el rendimiento total del sistema. En cuanto a la desincronización, incluso los procesos en la misma caja física no están sincronizados hasta que se crea y envía el mensaje de estado, es solo cuestión de dónde se vacía la tubería, la RAM local o la red.
Patrick Hughes
5

Utilice el filtrado del área de interés. Si un mundo se divide en 3 servidores, y el área del servidor 1 no está cerca del área del servidor 3, no hay ninguna razón para que compartan información sobre entidades.

Del mismo modo, en un solo servidor, solo envíe información relevante a los clientes. Si el jugador A está en el extremo totalmente opuesto del mapa del jugador B, no hay razón para enviar actualizaciones sobre B a A, o viceversa.

Cuando tiene varios servidores en un mundo continuo, tendrá entidades cercanas a un borde en el servidor 2 que están cerca de las entidades en el servidor 1. Puede enviar actualizaciones desde el servidor "autorizado" de una entidad al otro servidor (cuando corresponda) y del mismo modo reenviar cualquier mensaje al servidor autorizado según corresponda.

Sí, en este caso, un servidor estará un poco desactualizado para entidades particulares. No trates de resolver eso. Simplemente trata con ello. Suponga que las entidades pueden estar un poco desactualizadas. Haga cualquier lógica que necesite información actualizada solo en el servidor que posee las entidades con autoridad. Cuando una entidad afecta a otra, envía un mensaje y asume que puede tomar múltiples tics lógicos del juego antes de que se procese y tu vista se actualice.

Este diseño también hace que sea mucho más fácil enhebrar un solo servidor. Ninguna entidad debe modificar directamente a otra, solo enviar mensajes, y se debe suponer que las cachés de proxy locales por servidor / por subproceso están ligeramente desactualizadas.

Por ejemplo, si la entidad A ataca a la entidad B, no verifique la vida de B y luego envíe un mensaje de muerte si llega a 0. Simplemente envíe un mensaje "dañado", deje que el servidor autorizado de B lo maneje, y luego maneje cualquier Mensaje "entidad fallecida" enviado por el servidor B más tarde si la entidad A se preocupa por eso.

Lo mismo se aplica a cualquier aplicación grande y escalable que no sea de juegos. Una base de datos central no es una tecnología mágica para compartir instantáneamente. Dos servidores deben comunicarse con mensajes, asincrónicamente, en lotes, para mantener un alto rendimiento. De ahí la popularidad de tecnologías como AMPQ y similares. Las bases de datos son para el almacenamiento y la sincronización de soporte por necesidad, lo que les permite ser utilizadas para las comunicaciones, no porque estén destinadas a la sincronización o la comunicación.

Sean Middleditch
fuente
Gracias, esto terminó con la mayoría de mis dudas restantes. También me diste la idea de separar los servidores por jugadores, no por áreas, esto se vería mejor. Cada servidor se encarga de x jugadores. ¡Realmente me gusta esto! ¿Se usa esto? Y también, solo hay una cosa más. Como pregunté anteriormente, acabo de enterarme de una nueva base de datos NoSQL, Couchbase. Se supone que es como CouchDB, excepto con velocidades de escritura / lectura muy rápidas: ¡hasta 200k actualizaciones por segundo! ¿Quizás esto podría funcionar como un "modelo de mundo compartido en tiempo real", o aún no?
MaiaVictor
No tengo idea de si esa técnica se utiliza en la naturaleza además de la "fragmentación" de los servidores. Simplemente hacerlo por parte de los jugadores y el área geográfica significa que cada servidor puede necesitar conocer una gran cantidad de entidades en un conjunto diverso de áreas, lo que aumenta la carga del servidor y aumenta considerablemente la comunicación entre servidores. Hacerlo por área significa que su servidor podría sobrecargarse en áreas abarrotadas (aunque puede dividir y unir dinámicamente áreas en ese caso), pero significa que cada servidor tiene un conjunto más pequeño de entidades y geometrías relevantes que no son jugadores para realizar un seguimiento .
Sean Middleditch el
@Dokkat: Podría ser posible tener algún tipo de "áreas blandas" donde cada servidor maneje principalmente a los jugadores en una parte particular del mundo del juego, pero haga que entreguen el jugador de manera transparente a otro servidor si se alejan demasiado de la región de su servidor original. Solo debe asegurarse de que la entrega sea lo suficientemente suave como para que los jugadores realmente no lo noten. Incluso podría intentar utilizar algunas técnicas de adaptación sofisticadas para mantener grupos de jugadores interactuando en el mismo servidor, incluso si se encuentran en el límite de una región.
Ilmari Karonen
3

Probablemente le interesará este artículo sobre Gamasutra , donde los desarrolladores de Eve Online discuten cómo es posible ejecutar con éxito un juego con 400 000 jugadores activos ... en una base de datos SQL.

Liosan
fuente
2

No piense en la base de datos como un modelo de mundo compartido amable en tiempo real que almacena todo sobre todo en todo momento, como se habrá dado cuenta, eso no puede funcionar.

En su lugar, trate la base de datos más como un archivo de guardado actualizado automáticamente: actualiza la base de datos solo ocasionalmente, como cuando los jugadores inician o cierran sesión o se mueven de una zona a otra, o cada vez que sucede algo importante que no desea ser perdido en caso de un bloqueo del servidor.

Los servidores del juego deben mantener el estado mundial real en tiempo real, en la memoria, como en su ejemplo original. Ahora, el truco para el escalado horizontal es que no todos los servidores necesitan saber todo en cada momento . Por ejemplo, si el jugador A está jugando en la zona A en el servidor A, B servidor que ejecuta la zona B por lo general no necesita saber lo que el jugador A tiene en su mochila - y, si se hace necesario saber que por alguna razón (por ejemplo, debido a que el jugador B en la zona B lanza algún tipo de hechizo de espionaje remoto en A) solo puede pedir esa información al otro servidor .

Esto requiere que asigne responsabilidades claras a los servidores, de modo que cuando el servidor B quiera saber sobre la mochila del jugador A, sepa qué servidor tiene la información autorizada sobre eso. También es probable que desee incluir algún tipo de mecanismo de suscripción de actualización, de modo que, por ejemplo, el servidor B pueda decirle al servidor A " Tengo a alguien espiando al jugador A, manténgame informado sobre todo lo que hacen hasta que le diga lo contrario " . También queremos incluir algún tipo de sistema de transmisión global para eventos globales importantes que los jugadores puedan necesitar conocer sin importar dónde se encuentren; por supuesto, tales eventos también deberían registrarse en la base de datos, pero tenerlos transmitidos activamente a todos los servidores significa que los servidores no tendrán que seguir sondeando la base de datos para obtener actualizaciones.

Ilmari Karonen
fuente
Respuesta impresionante! Esto fue precisamente lo que estaba preguntando, gracias. Entonces, tal vez la clave sea dividir el servidor en áreas, manteniendo la lógica en la memoria. Sin embargo, podría agregar: acabo de enterarme de una nueva base de datos NoSQL, Couchbase. Se supone que es como CouchDB, excepto con velocidades de escritura / lectura muy rápidas: ¡hasta 200k actualizaciones por segundo! ¿Quizás esto podría funcionar como un "modelo de mundo compartido en tiempo real", o aún no?
MaiaVictor
@Dokkat no, no lo hará. Couchbase no es mágico.
Philipp
2

Otras respuestas han hecho un buen trabajo al señalar cómo usar una base de datos, y no usar una base de datos para la comunicación. Otro aspecto que podría considerar es clasificar sus actualizaciones en función de cómo la información debe comunicarse a otras entidades. En lugar de establecer comunicación con los servidores, puede distribuir sus mensajes y utilizar mecanismos pubsub para comunicar actualizaciones entre entidades. Por ejemplo, puede tratar la ubicación de manera diferente en función de quién está cerca de usted:

  • La ubicación precisa en tiempo real puede ser útil dentro del radio R
  • Las actualizaciones de ubicación menos precisas y menos frecuentes pueden ser útiles dentro del radio 2 * R
  • Es posible que no se necesite información de ubicación más allá del radio 2 * R

Puede comunicar información de ubicación para una entidad escaneando periódicamente las entidades dentro del radio 2 * R (o algún múltiplo de eso en función de la velocidad de actualización y la velocidad máxima de una entidad), y suscribiendo la entidad a la alimentación de ubicación precisa o imprecisa de la otra entidad.

Podría tener diferentes estrategias para diferentes tipos de información, agrupar elementos comunes en las mismas colas de mensajes o tener diferentes colas para mensajes que necesitan ir a diferentes entidades (o simplemente enviarlas al conjunto más amplio de entidades y descartar los mensajes si No son útiles).

David N
fuente