Imaginez un monde ouvert de plus de 500 joueurs avec des données changeant aussi rapidement que 20 mises à jour / joueur / seconde. La dernière fois que j'ai travaillé dans un MMORPG similaire, il utilisait SQL, donc il était évident qu'il ne pouvait pas interroger la base de données tout le temps. Au lieu de cela, il a chargé tous les lecteurs de la base de données en mémoire en tant qu'objets C ++ et les a utilisés. Autrement dit, il a été mis à l'échelle verticalement. Serait-il possible de rendre ce serveur évolutif horizontalement à la place? Existe-t-il une base de données conçue pour prendre en charge ce nombre de mises à jour simultanément?
mmo
data-structure
databases
scalability
MaiaVictor
la source
la source
Réponses:
Cas de test de 500 joueurs communiquant tous, soit 250 000 flux d'informations volant à 20 Hz. La bande passante interne pour cela serait, en supposant 100 octets par message, environ 500 Mo / s. Cela semble ambitieux. Surtout entre les processus.
Si vous séparez les joueurs en groupes de 100, cela diminue à 20 Mo / s, etc. C'est pourquoi les MMO ont des zones, et dans ces zones de petites bulles d'influence, et ainsi de suite jusqu'à ce que la bande passante devienne raisonnable.
Le problème d'origine peut être dit que si 10 personnes partagent toutes des informations en temps réel, mais que vous voulez 500 toutes , c'est une croissance exponentielle des liens de communication et comment pouvons-nous contourner cela . J'ai peur qu'il n'y ait aucune balle magique dont j'aie jamais entendu parler qui puisse magiquement faire disparaître la progression géométrique.
N'utilisez pas de base de données pour communiquer, c'est à cela que sert la messagerie. Utilisez la base de données pour appliquer les transactions et stocker les informations que vous ne voulez pas que les joueurs perdent. La plupart des MMO que je connais ne mettent à jour la base de données qu'avec des informations dynamiques sur le joueur toutes les 1 à 10 minutes, ou à des endroits pratiques comme des transitions de zone ou l'entrée dans des zones "sûres" dans la conception.
Vous devrez peut-être repenser les besoins du jeu pour chaque joueur, peu importe la distance, pour avoir des mises à jour en temps réel du contenu du sac à dos de chaque autre joueur.
Modifiez également le modèle de mise à jour de 20 Hz à une vitesse basée sur la distance, une personne à 1 mile de distance n'a pas besoin de savoir que vous vous êtes déplacé d'un pied à exactement 230,6 secondes, puis d'un autre pied à 231,4 secondes, ils peuvent gérer le déplacement de 15 pieds tous les 10 secondes.
la source
Utilisez le filtrage des zones d'intérêt. Si un monde est divisé en 3 serveurs et que la zone sur le serveur 1 est loin de la zone du serveur 3, il n'y a aucune raison pour qu'ils partagent des informations sur les entités.
De même, sur un seul serveur, envoyez uniquement les informations pertinentes aux clients. Si le joueur A se trouve à l'extrémité totalement opposée de la carte du joueur B, il n'y a aucune raison d'envoyer des mises à jour sur B à A, ou vice versa.
Lorsque vous avez plusieurs serveurs dans un monde continu, vous aurez des entités proches d'un bord sur le serveur 2 qui sont proches d'entités sur le serveur 1. Vous pouvez envoyer des mises à jour du serveur "faisant autorité" pour une entité à l'autre serveur (le cas échéant) et transférez également tous les messages au serveur faisant autorité, le cas échéant.
Oui, dans ce cas, un serveur sera légèrement obsolète pour des entités particulières. N'essayez pas de résoudre cela. Débrouille toi avec. Supposons que les entités soient un peu obsolètes. Effectuez toute logique nécessitant des informations à jour uniquement sur le serveur propriétaire des entités. Lorsqu'une entité en affecte une autre, envoyez un message et supposez que cela peut prendre plusieurs ticks de logique de jeu avant d'être traité et que votre vue soit mise à jour.
Cette conception facilite également le thread d'un seul serveur. Aucune entité ne doit en modifier directement une autre, envoyer uniquement des messages, et les caches proxy locaux par serveur / par thread doivent être supposés être légèrement obsolètes.
Par exemple, si l'entité A attaque l'entité B, ne vérifiez pas la durée de vie de B et n'envoyez pas de message de mort s'il atteint 0. Envoyez simplement un message "endommagé", laissez le serveur faisant autorité pour B le gérer, puis gérez tout message "entité morte" envoyé ultérieurement par le serveur B si l'entité A s'en soucie.
Il en va de même pour toute application non ludique de grande taille. Une base de données centrale n'est pas une technologie magique de partage instantané. Deux serveurs doivent communiquer avec les messages, de manière asynchrone, par lots, afin de maintenir un débit élevé. D'où la popularité de technologies comme AMPQ et similaires. Les bases de données sont destinées au stockage et prennent en charge la synchronisation par nécessité, ce qui leur permet d'être utilisées pour les communications, non pas parce qu'elles sont elles-mêmes destinées à la synchronisation ou à la communication.
la source
Vous serez probablement intéressé par cet article sur Gamasutra , où les développeurs d' Eve Online expliquent comment il est possible de réussir un jeu avec 400 000 joueurs actifs ... dans une base de données SQL.
la source
Ne pensez pas à la base de données comme une sorte de modèle mondial partagé en temps réel stockant tout sur tout à tout moment - comme vous l'avez remarqué, cela ne peut pas fonctionner.
Au lieu de cela, traitez la base de données plus comme un fichier de sauvegarde mis à jour automatiquement: vous ne mettez à jour la base de données qu'occasionnellement, comme lorsque les joueurs se connectent ou se déconnectent ou se déplacent d'une zone à une autre, ou chaque fois qu'un événement important se produit que vous ne voulez pas être perdu en cas de panne du serveur.
L'état réel du monde en temps réel doit être conservé par les serveurs de jeu, en mémoire, comme dans votre exemple d'origine. Maintenant, l'astuce pour la mise à l'échelle horizontale est que tous les serveurs n'ont pas besoin de tout savoir à chaque instant . Par exemple, si le joueur A joue dans la zone A sur le serveur A, zone B serveur exécutant B n'a généralement pas besoin de savoir ce que le joueur A a dans son sac à dos - et, si elle ne le besoin de savoir que pour une raison quelconque ( par exemple, parce que le joueur B dans la zone B lance une sorte de sort d'espionnage à distance sur A) il peut simplement demander cette information à l'autre serveur .
Cela vous oblige à attribuer des responsabilités claires aux serveurs, de sorte que lorsque le serveur B veut connaître le sac à dos du joueur A, il saura quel serveur dispose des informations faisant autorité à ce sujet. Vous voudrez probablement également inclure une sorte de mécanisme d'abonnement aux mises à jour , de sorte que, par exemple, le serveur B puisse simplement dire au serveur A " J'ai quelqu'un qui espionne le joueur A, tenez-moi au courant de tout ce qu'ils font jusqu'à ce que je vous dise le contraire. " veulent également inclure une sorte de système de diffusion mondial pour les événements mondiaux importants que les joueurs peuvent avoir besoin de savoir, peu importe où ils se trouvent; bien sûr, ces événements doivent également être enregistrés dans la base de données, mais leur diffusion active sur tous les serveurs signifie que les serveurs n'auront pas à continuer d'interroger la base de données pour les mises à jour.
la source
D'autres réponses ont fait un bon travail en indiquant comment utiliser une base de données et non pas utiliser une base de données pour la communication. Un autre aspect que vous pourriez examiner est de classer vos mises à jour en fonction de la façon dont les informations doivent être communiquées à d'autres entités. Plutôt que d'étendre la communication aux serveurs, vous pouvez distribuer votre messagerie et utiliser des mécanismes pubsub pour communiquer les mises à jour entre les entités. Par exemple, vous pouvez traiter l'emplacement différemment en fonction de vos proches:
Vous pouvez communiquer des informations de localisation pour une entité en recherchant périodiquement des entités dans le rayon 2 * R (ou un multiple de celui-ci en fonction du taux de mise à jour et de la vitesse maximale d'une entité), et en abonnant l'entité au flux de localisation précis ou imprécis de l'autre entité.
Vous pouvez avoir différentes stratégies pour différents types d'informations, regrouper les éléments communs dans les mêmes files d'attente de messages, ou avoir différentes files d'attente pour les messages qui doivent aller à différentes entités (ou simplement les envoyer à l'ensemble d'entités le plus large et faire supprimer les messages s'ils ne sont pas utiles).
la source