Comment mmorpg stocke-t-il les données?

22

Je veux utiliser la base de données SQL dans mon server.exe.

disons 1000 utilisateurs en ligne. Et les joueurs changeront leurs données lorsqu'ils joueront. Et le serveur doit enregistrer ces mises à jour.

Mais comment ?

je pense qu'il y a deux sens:

1) le serveur enregistre dans le ram au moment de l'exécution et parfois ou toutes les heures, le serveur écrit les données (mise à jour) dans la base de données SQL à partir du ram. Mais si l'électricité se coupe ou que le serveur s'arrête, les mises à jour ne seront pas enregistrées. bien sûr, je ne veux pas perdre les mises à jour.

2) le serveur enregistrera les mises à jour dans la base de données au moment de l'exécution. mais qu'arrivera-t-il pour accélérer? J'ai pensé à une méthode. je vais vous montrer ci-dessous avec l'image. Puis-je obtenir suffisamment de vitesse pour 1000 joueurs en ligne avec cette méthode? entrez la description de l'image ici

Emre Kaya
la source
11
Avez-vous fait des repères? Qu'est-ce qui vous fait penser que les opérations de base de données seraient un problème pour votre jeu?
congusbongus
3
Si votre état de jeu est réellement relationnel? Voulez-vous vraiment une base de données SQL?
Arrêtez de nuire à Monica le
6
Veuillez également lire comment gérer les mots de passe à l'aide de hachages. Ou au moins, informez l'utilisateur que son mot de passe est enregistré en texte brut, afin qu'il soit conscient de ne pas utiliser un autre mot de passe sécurisé.
TomTsagk
24
En remarque, si vous souhaitez créer un MMO commercial et que vous posez des questions comme celle-ci, vous devriez probablement commencer par quelque chose de plus petit. Les MMO sont incroyablement difficiles à faire, encore moins à bien les faire, et ils ne sont pas si bons d'un point de vue commercial. Si ce n'est qu'une affaire personnelle et que vous souhaitez augmenter le nombre de joueurs, commencez par quelque chose comme 64 joueurs, puis montez. Ce sera beaucoup plus facile que d'essayer de concevoir l'architecture "parfaite" à partir de zéro sans aucune expérience. Regardez ça .
Fund Monica's Lawsuit
1
Vous pouvez écrire une API générale indépendante du stockage. Ensuite, écrivez un adaptateur qui met en cache les données dans la RAM pour un stockage retardé. Ou vous pouvez écrire un adaptateur qui met en cache les données dans un fichier temporaire avant de les vider dans SQL DB. De cette façon, vous pouvez activer et désactiver la mise en cache pour savoir laquelle est la meilleure. Vous n'avez pas besoin d'écrire trop de code supplémentaire, si votre architecture est bien construite.
0xC0DEGURU

Réponses:

37

La plupart des MMO (ou projets utilisant une architecture similaire) sur lesquels j'ai travaillé ou que je connais utilisent la première méthode: les serveurs de jeux fonctionnent principalement avec la RAM sur les machines exécutant les processus serveur et ne sérialisent que périodiquement les données de jeu pertinentes dans une base de données SQL pour l'archivage (s'il y en a un).

Les problèmes que vous notez concernant la panne de courant sont valides, mais moins susceptibles que des problèmes tels que les plantages dans le processus (la fiabilité de la disponibilité est généralement l'une de ces choses pour lesquelles vous paieriez le centre de données). Mais reste. Vous atténuez ces problèmes grâce à des choses comme le réglage de l'intervalle de sauvegarde (donc une panne ne coûte que quelques minutes au maximum), la distribution des files d'attente de sauvegarde sur plusieurs machines, l'étendue agressive de la quantité de données qui doit être sauvegardée et l'implémentation de la sauvegarde redémarrable files d'attente.

De manière générale, l'utilisation du serveur SQL lui-même comme mémoire principale sera désagréablement lente (et lourde). Je ne vois pas suffisamment de détails dans votre proposition pour pouvoir dire avec certitude si cela fonctionnerait pour seulement environ 1000 joueurs - ce serait probablement bien. Mais je ne pense pas que vous puissiez le rendre évolutif de manière agressive.

De plus, cela ne résout pas le problème. Une panne de courant pendant le processus de sauvegarde perdra ou corrompra des données, sauf si vous effectuez le travail pour implémenter le même type de file d'attente de sauvegarde redémarrable (ce qui, même alors, ne réduit que gravement la probabilité de perte de données catastrophique, il ne l'empêche pas) .

Je vous recommande d'aller avec la première approche.


la source
10
En ce qui concerne "le réglage de l'intervalle de sauvegarde", le dernier MMO sur lequel j'ai travaillé avait un intervalle de sauvegarde basé sur le nombre de joueurs actifs. Nous savions qu'il pouvait gérer la sauvegarde des données des joueurs X par seconde sans goulot d'étranglement notable, nous l'avons donc juste fait économiser un peu moins de X joueurs par seconde sur une base rotative. Cela finissait généralement par être une sauvegarde pour chaque joueur toutes les deux minutes environ les jours occupés, et peut-être deux fois par minute pendant les périodes lentes.
Meanbits
4
"File d'attente de redémarrage" ressemble à un journal, comme l'implémentent de nombreux systèmes de fichiers et moteurs de base de données?
grawity
6
Ces questions ne sont pas uniques à MMOs, ou même des jeux vidéo, du tout . Presque tous les ORM existants fournissent une sorte de mécanisme de mise en cache / traitement par lots. Il n'est pas nécessaire de lancer votre propre solution.
BlueRaja - Danny Pflughoeft
3
Si vous finissez par enregistrer sur un disque à un certain intervalle, je recommanderais de concevoir un système où les choses peuvent être enregistrées immédiatement, lorsque les gens obtiennent une chute / mort / etc. rare. De cette façon, s'il y a un crash de serveur ou quelque chose, les gens qui ont accompli quelque chose de gros ne seront pas trop contrariés.
Jon
5
@Jon, puis vous rencontrez le problème des personnes capables de dupliquer des objets. Idéalement, vous enregistrez périodiquement l'ensemble de l'état du jeu en une seule transaction. Une fois que vous avez commencé à enregistrer par morceaux, vous vous retrouvez avec des situations où un crash peut provoquer des données incohérentes; les joueurs qui peuvent déclencher un crash à la demande, ou même prédire quand un crash est susceptible de se produire, peuvent exploiter cela à leur avantage.
Mark
15

Le joueur 1000 peut ou peut ne pas être un problème. Cela dépend de la fréquence à laquelle vous devez mettre à jour la base de données. Cependant, il existe une solution simple: mettre la base de données sur son propre serveur.


J'ai eu un aperçu du fonctionnement du système de base de données un jeu que les gens appellent un MMO-Lite - lequel je ne divulguerai pas - mais je peux dire qu'il a toujours plus de 1000 joueurs, voici le résumé:

  • Ils utilisent une base de données "No-SQL" basée sur des documents pour les informations de caractère privé (inventaire, équipement, similaire).
  • Ils utilisent une base de données relationnelle plus traditionnelle pour les informations de caractère public qui sont rarement mises à jour (nom, réalisations, etc ...) et les statistiques.

L'utilisation d'une base de données basée sur des documents s'avère être une bonne idée de performances dans ce cas. C'est bon pour accéder aux données, même si c'est mauvais pour faire des jointures et des agrégations ... mais ils ne le feront pas avec les données qui s'y trouvent.

D'un autre côté, quand ils doivent faire quelque chose comme changer un objet avec un autre objet pour tout le monde, la nécessité d'exécuter un script d'arrière-plan qui va caractère par caractère et les met à jour un par un, cela prend du temps.


Les données du personnage existent à la fois sur le client et sur le serveur, et le système est conçu pour les synchroniser, en effectuant les mêmes opérations des deux côtés.

Désormais, lorsqu'un joueur effectue une transaction avec le système - disons échanger un objet contre un autre via un PNJ ou similaire - cela comporte les étapes suivantes:

  • Les clients vérifient si l'opération est valide
  • Le client envoie l'opération au serveur (opération asynchrone)
  • Le client met à jour son modèle en RAM
  • Le serveur vérifie si l'opération est valide
  • Le serveur met à jour son modèle en RAM
  • Le serveur met à jour la base de données (opération asynchrone)
  • Le serveur informe le client que le changement s'est produit

Remarques :

  • Les mises à jour de la base de données, bien qu'async, sont effectuées immédiatement. Si pour une raison quelconque le serveur de jeu tombe en panne, il n'y a pas grand-chose à perdre.
  • La dégradation des performances n'est pas un gros problème grâce au placement des bases de données sur leurs propres serveurs.

Les échanges entre les joueurs sont traités de la même manière, avec des règles supplémentaires pour empêcher les joueurs d'escroquer d'autres joueurs et une traçabilité supplémentaire au cas où une transaction devrait être annulée. J'ai entendu dire qu'il existe des journaux spéciaux de toutes les transactions qui sont conservées pendant un certain temps (pour résoudre les problèmes lorsque quelqu'un se plaint), je ne sais pas plus comment cette partie fonctionne.


Parfois, quelque chose ne va pas, cela a deux résultats possibles:

  • Si l'erreur se produit tout de suite, le serveur en informera le client, qui annulera l'opération (le joueur voit l'opération annulée).
  • L'interface utilisateur indique que le joueur a un élément, mais le serveur n'est pas d'accord. Si l'utilisateur essaie de l'utiliser, il demandera au serveur et échouera, rendant le faux objet inutilisable. Le faux objet disparaît lorsque l'inventaire est rechargé, ce qui est l'occasion de synchroniser le modèle.

Dans les deux cas, le client est conscient de l'erreur et l'enregistrera avec tout ce que le joueur faisait. La journalisation côté client se produit tout le temps. Ensuite, à la déconnexion, en cas d'erreur, le client envoie les journaux au serveur.


Ce jeu n'utilise pas le temps d'arrêt d'entretien quotidien ou hebdomadaire traditionnel de la plupart des MMORPG. Cette maintenance planifiée est souvent utilisée pour réinitialiser les compteurs, les minuteurs et exécuter les procédures de base de données. Ils sont également l'occasion d'échanger des versions de serveur pour une mise à jour.

Theraot
la source
Merci, mais qu'en est-il des mouvements des joueurs par exemple, si un joueur se déplace de sa position actuelle: x:10,y:10,z:10À x:11,y:11,z:11, cela devrait-il être enregistré immédiatement dans la base de données? que se passe-t-il si le joueur continue de fonctionner, cela signifie que nous enregistrons sa position actuelle toutes les 1s ou moins, et s'il y a des milliers de joueurs, c'est des millions de requêtes à la base de données chaque seconde. Est-ce ainsi que cela fonctionne?
dwix
2
La position du joueur doit être enregistrée très rarement dans la base de données. Vous ne voudriez que cela lors d'occasions spéciales comme l'ouverture du menu, l'allumage d'un feu de camp, le repos, etc. Selon le jeu, il ne sera même pas enregistré de manière aussi détaillée. Certains jeux vous font toujours apparaître dans la ville la plus proche, etc., ce qui vous éviterait également de perdre la position. Mais cela dérive en fonction de l'opinion.
Nico
1
@dwix dans le cas du jeu dont je parle, la position du joueur n'est même pas enregistrée. Si vous vous déconnectez et vous connectez, ou si le serveur tombe en panne, le joueur sera replacé à une position connue et sûre (modifier: c'est une instance privée, "maison" si vous voulez, mais c'est la même chose pour tout le monde). Cependant, certains jeux conservent la position exacte du joueur, même en cas de déconnexion accidentelle. Pour ce faire, l'approche habituelle consiste à stocker ces informations moins fréquemment. Quoi qu'il en soit, vous n'avez pas ce que le serveur attend sur la base de données.
Theraot
1
@dwix quand on parle de la position de l'avatar, vous ne vous souciez pas vraiment des valeurs historiques, n'est-ce pas? Eh bien, si la base de données est un goulot d'étranglement, réduisez les données. Au lieu de stocker chaque tick de serveur, stockez moins fréquemment. Cela signifie que la base de données n'aura pas la valeur la plus récente, mais elle n'aura pas d'impact sur les performances si fortement. Pendant ce temps, le serveur conservera toujours la valeur de mise à jour dans la RAM, et c'est avec cela qu'il fonctionne. Addendum: honnêtement, je déconseille de stocker les positions, mais certains jeux le font.
Theraot
1
@dwix voir le commentaire des méchants
Theraot
7

Les deux approches sont utilisées avec les MMORPG. Garder tout en mémoire et vérifier périodiquement le pointer vers le disque semble être l'option la plus populaire, au moins pour les jeux plus anciens. Il a l'avantage d'être assez simple à implémenter et à évoluer assez bien, mais sa fiabilité est entièrement à la charge du développeur. Les bases de données SQL fournissent des propriétés ACID qui facilitent la fiabilité, mais sont globalement plus compliquées à mettre en œuvre correctement et peuvent avoir des problèmes de mise à l'échelle.

EVE Online est un exemple de MMO où tout est stocké dans une base de données SQL. Je pense qu'il a culminé à quelque 60 000 utilisateurs simultanés et a dû consacrer du matériel coûteux aux serveurs de base de données au fil des ans afin de suivre la charge. Cependant, EVE stocke beaucoup plus de données par utilisateur que la plupart des MMORPG et a des transactions beaucoup plus fréquentes et variées. Les propriétés ACID de la base de données permettent à l'ensemble de la base de données massive et compliquée d'être toujours maintenue dans un état cohérent.

Par exemple, considérons le cas où quelqu'un donne un objet à un autre joueur. La base de données d'EVE garantit que même en cas de crash ou de panne de courant, l'objet se retrouve dans l'inventaire d'un seul joueur. Autrement dit, la transaction de base de données qui supprime l'élément de l'inventaire d'un joueur et l'ajoute à celui de l'autre joueur est atomique. La transaction se termine complètement ou ne se produit pas du tout. Vous ne pouvez pas vous retrouver dans un état où l'objet n'existe dans l'inventaire des joueurs ou dans les deux.

Un MMORPG qui garde les données des joueurs en mémoire et vérifie périodiquement les points qu'il doit mettre en œuvre lui-même cette atomicité. Une façon de le faire serait de vérifier les données de chaque joueur en même temps, en s'assurant que le nouveau point de contrôle est entièrement validé sur le disque avant d'être considéré comme le point de contrôle le plus récent. Le jeu devrait également garantir que les données des joueurs ne peuvent pas changer pendant leur contrôle. Avec une grande quantité de joueurs actifs, le défi devient de faire tout cela sans causer un retard suffisamment long pour que les joueurs le remarquent.

Ne sous-estimez pas l'importance de la cohérence. Lorsque vous développez votre jeu, ça va planter beaucoup. Vous ne voulez pas avoir à rechercher pourquoi les éléments disparaissent et / ou dupliquent, pas lorsque le problème est un bug sans rapport qui provoque le crash du jeu à un mauvais moment. De plus, lorsque votre jeu sera mis en ligne, il plantera beaucoup plus que vous ne le pensez. Votre serveur qui fonctionnait parfaitement sous test, exposera soudainement de nombreux bogues à pleine charge et les joueurs font ce que vous ne vous attendiez pas.

Notez que la plupart des MMORPG utilisent des bases de données SQL pour les informations liées aux comptes, même si elles ne le sont pas pour les données de jeu réelles. Encore plus important que de maintenir l'état du jeu dans un état cohérent est de maintenir l'état de facturation cohérent. Le pire cas de corruption de la base de données du jeu est que vous devez restaurer la base de données à partir d'une sauvegarde quotidienne. Le pire cas de corruption de la base de données des comptes est que vous faites faillite en raison de tous les débits compensatoires.

Pour votre projet, vous pouvez probablement aller dans les deux sens. Avoir 1000 utilisateurs simultanés ne repoussera probablement pas les limites de ce qu'un serveur SQL peut gérer sur un PC standard ces jours-ci, mais beaucoup dépendra de la nature des transactions. Si vous êtes familier avec la conception de bases de données relationnelles et SQL, cela peut fonctionner pour vous. Vous souhaiterez minimiser les transactions autant que possible, pour quelque chose comme les points de vie actuels des joueurs, vous ne voudrez peut-être que les enregistrer périodiquement dans la base de données, car ces statistiques n'ont pas nécessairement besoin d'être cohérentes. (Dans le jeu PvP, ils pourraient cependant ...) Ne stockez pas du tout les monstres HP dans la base de données, dans la plupart des jeux, seules les données relatives aux joueurs sont persistantes.

D'un autre côté, si vous n'êtes pas un assistant SQL, vous trouverez peut-être beaucoup plus simple de conserver toutes les données en mémoire pour travailler de manière fiable. Les bases de données SQL facilitent la cohérence et la fiabilité, mais ce n'est pas automatique. Une base de données mal conçue peut mal fonctionner et entraîner des incohérences. Les transactions ne seront atomiques que si vous le faites. Si vous n'utilisez pas religieusement des instructions paramétrées, vous vous exposerez aux attaques par injection SQL.

Ross Ridge
la source
0

Divers jeux stockent les choses de différentes manières. Souvent, les sociétés de jeux créent un moyen de le faire, et la plupart de leurs jeux utilisent la même manière. Bien sûr, différents studios utilisent souvent des méthodes différentes. SQL est certainement utilisé pour les jeux, par exemple CCP (EVE) a (ou du moins avait) un réseau de serveurs SQL, je ne sais pas comment ils le font maintenant. Pour d'autres, il suffit d'utiliser de nombreux fichiers.

Peut-être commencer par créer un "mécanisme de courtage de données" agnostique, pour gérer diverses transactions de données de jeu? Comme vous ne faites que tester de toute façon, créez un mécanisme qui vous permet de ne pas trop vous soucier du stockage, du point de vue du jeu lui-même. C'est-à-dire, concentrez-vous sur la façon dont, à partir de l'application hôte, vous allez gérer cela.

Personnellement, je pense que ce serait un grand atout si vous pouviez changer de magasin, sans avoir à réécrire le jeu et le courtier lui-même. Passez simplement à un autre module avec la même interface pour que le courtier puisse parler.

Le stockage des données en soi ne sera probablement pas un problème en soi. Expédier efficacement des données, vers / depuis ce magasin, entre l'hôte et tous les clients, pourrait être plus délicat. Dois-je expédier l'ensemble des données du lecteur, ou si je le décompose en parties, quelle granularité dois-je choisir de partitionner, etc. Laquelle est la plus gourmande en ressources dans quelle situation, etc.

Un format dans lequel envoyer les données pourrait être XML. De cette façon, vous pouvez plus facilement être dynamique dans la façon dont vous pouvez le fragmenter. Un caractère par rapport à plusieurs caractères, ou un élément par rapport à une collection d'éléments, etc. Vous pouvez alors soit «stocker» le XML en XML (en SQL), et / ou demander à SQL de le distribuer de manière plus transactionnelle à partir du XML, vers comment vous voulez que les données soient réellement stockées.

Une autre façon est binaire, qui est plus efficace en termes d'expédition, mais peut entraîner des coûts plus élevés dans d'autres situations.

Avec 1000 clients, vous pouvez commencer et stocker facilement 10 Mo par client et n'utiliser que 10 Go de RAM efficace + ajouter de la RAM administrative système pour gérer ces données, disons un autre Go ou deux. Vous pouvez garder cela en RAM sur l'hôte déjà dans la structure de données prêt à l'emploi. Et chargez / enregistrez dynamiquement, selon qui est en ligne, à différentes fréquences selon l'activité, etc.

Vous pouvez même stocker les informations de chaque client dans un fichier séparé, etc.

Rob
la source
0

Gardez les joueurs * en ligne * dans ram et poussez-les dans une base de données (SQLite? MySQL?) Lorsqu'ils se déconnectent. si vous vous inquiétez du blocage des entrées-sorties pendant la déconnexion, donnez à chaque déconnexion son propre fil de discussion, ne le faites pas dans le fil principal / jeu (en fait, je garde un fil de lecteur dédié pour chaque joueur en ligne, cela a rendu le code de mise en réseau tellement plus facile que de faire l'approche réseau io asynchrone)

hanshenrik
la source