mmofacts.com

DB oder im Arbeitsspeicher

gepostet vor 16 Jahre, 9 Monate von altertoby
Hi hab mal ne Frage,
für welche Userzahlen (oder von was es halt noch abhängt) ist es besser die Daten in einer DB zu speichern oder im Arbeitsspeicher des Servers?
also beim 2. hab ich mir ein Programm geschrieben, welche die Daten aus der DB einmal ausließt (DB=Backup) und dann von der eigentlichen Webseite per RemoteServer die Eingaben zugesandt bekommt.
Jedoch ist nur ein Teil des BG so aufgebaut, nämlich der wo viel Rechenarbeit mit den Daten verlangt ist und eine ständige Ausfrage der DB zu viel Zeit kosten würde (zb Flottensteuerung, Kämpfe berechnen, ect)
Meine Frage ist jetzt ob es sich lohnt alles nach dem 2. Prinzip umzugestalten und was ihr für Probleme seht? oder ob es sogar unperformater wäre als ne normale DB
(ich weiß nur nicht was passiert wenn man mehrere Server hat, dann müssten die Daten sich ja auf 2 Programme auf 2 Server aussplitten)
EDIT: ich benutze c# bzw asp.net
gepostet vor 16 Jahre, 9 Monate von Nuky
Im normalfall ist der Versand dieser Daten über Remote-Prozeduren mehr aufwand als die Berechnung selbst - mehr Informationen könnten eine bessere Antwort ergeben
gepostet vor 16 Jahre, 9 Monate von altertoby
also eingesetzt wird es atm in folgenden Bereichen:
1. Fertige Bauschleifen herrausfinden (in der DB wird abgespeichert wann es fertig ist und es soll möglichst zu diesem Zeitpunkt auch fertig sein...also bekommt das Programm gesagt, wenn die Bauschleife fertig ist und startet dann intern nen Timer der das auf wenige Sekunden genau macht. (dürfte performater sein als jede sekunde die DB abzufragen ob ne Bauschleife fertig ist oder?)
2. Herrausfinden ob gekämpft werden soll:
Da wird auch jede sekunde von allen Flotten die position berechnet und dann mit den anderen verglichen und ggf der Kampf ausgelöst (da das relativ viel berechnen ist dürfte es auch wieder schneller als über ne DB sein)
3. last but not least auch noch beim Berechnen der Kämpfe:
also welches Schiff welches andere Schiff abschießt und so (soll aber aller 5 min eine Runde sein...also wäre es für die DB alle 5 min die daten hohlen und rechnen... für das Prog ist es einfach einmal Daten bescheid bekommen und dann nur noch rechnen)
Daten mit denen kaum gerechnet wird sind normal in der DB, aber werden zb auch bei den Kämpfen evt gebraucht (zb welche Rassenboni bekommt der User ect)
hoffe das sind genügend Infos, wenn nicht dann frag(t) einfach!
Thx schonmal für die Hilfe
gepostet vor 16 Jahre, 9 Monate von Klaus
wichtige Zahlen würde ich schon im RAM vorhalten. Für alles hast du aber kaum Platz dafür, denn sonst platzt aufgrund von PNs oder sonstigen irgendwann der Speicher.
Also ich würde das weiterhin so wie du machen und evtl. den Cache der DB runterschrauben, da sowieo nur noch selten abgefragte Daten dort liegen.
gepostet vor 16 Jahre, 9 Monate von Kampfhoernchen
Schön dafür wären auch MySQL Heap-Tabellen. Die sind extrem fix bei sowas, und wenn zu viel RAM gebraucht wird, swappen sie automatisch auf die Platte.
gepostet vor 16 Jahre, 9 Monate von altertoby
@Klaus:
jo schon klar, dass viele Daten entstehen... aber wenn mich nicht alles täuscht wird doch, wenn der Ram zu klein ist das vom BS automatisch auf die Platte gehauen oder?
also wäre es ja das gleiche wie die Heap-Tabellen (kenn ich persönlich nicht, werd ich mir gleich mal ankucken aber von dem was Kampfhoernchen geschrieben hat).
Mein Problem ist es atm einfach, dass zb das Kampfberechnen Programm zb die User-Rassen-Zugehörigkeit braucht (und noch nen paar andere Sachen auch).
Wenn ich die bei jedem Durchlauf aus der DB hohle wäre es auch net so toll (dann wäre ja ein großer Vorteil des Progs teilweise weg) und wenn ich es wie bei den eigentlichen Daten mache (also von der Webseite benachrichtigen lasse bei Veränderungen) dann hab ich im Endeffekt fast alle Daten im Prog
Also was mache ich mit den Daten die relativ klein sind (die Rassen sind ja einfach ne int bzw enum) und ich relativ oft brauch?
Irgendwie würde es dann darauf hinauslaufen dass nur noch die großen Daten die bei keiner einzigsten Berechnung gebraucht würden (wofür brauch ich bitte PNs zur Berechnung?) in der DB gespeichert würden (und DB)...
Gefällt mir das jetzt oder nicht?
gepostet vor 16 Jahre, 9 Monate von KoMtuR
Also ich würde solche Sachen, die sich im Spiel nicht wirklich ändern, wie auch deine Rassen, nicht explizit in einer Datenbank speichern. Dafür ist es doch optimal, dies dann in einer Config-Datei zu speichern (von mir aus XML) und diese bei Start der Applikation im Speicher zu halten. Solche Sachen werden den Ram sicherlich nicht auslasten, da es doch relativ wenige Daten sind.
Sachen wie Flottenbewegungen u.ä., welche sich immer ändern und auch irgendwo gespeichert werden müssen, würde ich dahingegen natürlich in eine Datenbank hauen, um damit gut hantieren zu können. Das das Bestriebssystem auch automatisch swapt ist ja nur gut für deine Anwendung.
Auch brauchst du weniger Verbindungen zu deiner Datenbank, wo dann dein Connection-Pool für wichtigere Sachen offen bleibt und Sachen, die wirklich in der DB stehen warten müssen, bis wieder Verbindungen frei sind.
Ich handhabe es auch so, dass ich statische Daten eher in ne Konfigurationsdatei haue und wirklich ändernde Sachen in die DB haue. Ist zwar mit Java, aber da nehemn sich die Sprachen ja nicht wirklcih viel
gepostet vor 16 Jahre, 9 Monate von altertoby
Hi KoMtuR,
ich glaub du hast mich leicht falsch verstanden
Die wirklich rein statischen Daten sind natürlich nicht in der DB, die sind wie du bereits empfohlen hast in XML-Dateien (und auch schön im Speicher).
Das ist nicht das Problem, sondern zb welcher User welcher Rasse angehört...
Ansich ein klarer Fall, aber wenn das Kampfsystem die eigentlich komplett laden muss aller 5 min (und da ist das User-Rasse-Problem noch das einfachste mit 5 min) bin ich nicht so wild darauf
Es ging mehr darum, dass man auch solche halbwegs statischen (Rassen können sich auch ändern) Daten auch im Speicher behält wenn man sie öfter braucht... oder ob es trotzdem performater diese Daten in ne DB zu hauen!
Also:
a) Daten, die völlig statisch sind: XML-Dateien und werden im Speicher gehalten
b) Daten, die nahezu statisch sind und kaum für Berechnungen gebraucht werden: DB
c) Daten, die nahezu statisch sind aber öfter gebraucht werden: Programm (also Speicher) oder DB?
d) Daten, die sich öfter verändern und auch öfter für Berechnungen gebraucht werden: Programm
also die Frage ist was ist das Beste im Umgang mit c)-Daten (und evt. d)-Daten)
gepostet vor 16 Jahre, 9 Monate von RaydenDD
Original von altertoby
a) Daten, die völlig statisch sind: XML-Dateien und werden im Speicher gehalten
b) Daten, die nahezu statisch sind und kaum für Berechnungen gebraucht werden: DB
c) Daten, die nahezu statisch sind aber öfter gebraucht werden: Programm (also Speicher) oder DB?
d) Daten, die sich öfter verändern und auch öfter für Berechnungen gebraucht werden: Programm

Stimme zu
c würd ich auch in RAM laden
Ich kann dir ein Beispiel aus meinem Spiel geben: die Planetendaten, die werden
- oft gebraucht
- sind überhaupt nicht statisch (ändern sich oft)
Die halte ich zB auch im RAM weil sie extrem oft benötigt werden, auch das ändern dieser Daten geht jetzt sehr fix weil sie ja im RAM sind . Ich speichere die Daten allerdings in bestimmten Zeitabständen in die Datenbank, da teilweise auswertungen durchgeführt werden müssen, für die ich nicht unbedingt die Suchalgorithmen der Datenbank nachprogrammieren will
gepostet vor 16 Jahre, 9 Monate von Drezil
Generell mal zu sowas:
Original von altertoby

3. last but not least auch noch beim Berechnen der Kämpfe:
also welches Schiff welches andere Schiff abschießt und so (soll aber aller 5 min eine Runde sein...also wäre es für die DB alle 5 min die daten hohlen und rechnen... für das Prog ist es einfach einmal Daten bescheid bekommen und dann nur noch rechnen)
Wieso musst du die daten ständig holen? Da du mit C# arbeitest, müsste es doch ein leichtes sein einen kamp-thread zu starten .. und sooo viele Daten wird dein Kampfsystem nicht haben.
Ich hab solche getimeten/rechenintensiven sachen alle in jeweiligen threads innerhalb meines c++-daemons.
gepostet vor 16 Jahre, 9 Monate von Agmemon
Ich bin ehrlich und halte das Verfahren, viele Daten im Speicher zu halten, für gefährlich:
1. Je mehr aktive Spieler man im Spiel hat, desto mehr Daten müssen im RAM vorgehalten werden. Die RAM Größe hat also einen starken Einfluss darauf, in wie weit das Vorgehen Vorteile bietet. Fängt das System an zu swappen. Die mittlere Zugriffszeit steigt dabei drastisch an. Und auch Prozesswechsel können sich stark verlangsamen.
2. Man muss sehr viel Aufwand treiben, um Atomarität, Konsistenz und Isolation in den Aktionen mit den Daten zu gewährleisten.
3. Das Verfahren arbeitet mit den Daten, als wären sie transient. D.h. die Dauerhaftigkeit ist nicht sichergestellt. Es müssen also Mechanismen geschaffen werden, die sicherstellen, dass Daten nicht verloren gehen, z.B. durch einen Systemabsturz. Das läuft also darauf hinaus, dass man die Daten regelmässig wegschreiben muss. Ist das Intervall zu groß, riskiert man Datenverluste. Ist das Intervall zu klein, gehen die Vorteile schnell wieder verloren.
4. Man muss sich eigene Mechanismen für den Datenzugriff und die Indizierung schaffen. Verfahren, in denen man immer erst mal über den Datenbestand iterieren muss, machen den Vorteil vermutlich auch wieder kaputt.
Wenn man ähnlich viel Energie und Zeit in das Datenbankdesign steckt und ein vernünftiges Vorgehen innerhalb der Anwendung wählt, bekommt man vermutlich ein besseres Ergebnis, was die Gesamtleistung betrifft. Man darf nicht alles nur unter dem Aspekt der Performance sehen.
gepostet vor 16 Jahre, 9 Monate von Klaus
1. Daher sollte man den Verbrauch auch im Auge behalten und ggf. pro Spieler berechnen. Bei solchen Dingen mache ich mir schon doppelt Gedanken darüber, ob ich nun einen Integer, ein Byte oder gar nur ein Bit für die einzelne Variable reserviere.
2. Wieso viel Aufwand? Threads kann man locken, Zugriffe mit gettern und settern kapseln.
3. Ich sage einfach mal ganz hart: Spieldaten aus 10 Minuten sind opferbar.
4. Erststart: Deserialisiere alle Daten von der Platte in Arrays, Objekte, whatever. Im laufenden Betrieb kann man dann ganz einfach auf die Daten zugreifen. Ein Array hat bereits einen Index und wenn ich nach Inhalt suchen müsste, dann kann eine Datenbank auch nicht wesentlich schneller arbeiten als alles durchzugehen.
Im Optimalfall läuft aber alles über den Index, z.B. die Spieler-ID oder eine Kartenkoordinate.
Dadurch spart man sich neben dem jit-Laden der Daten auch noch den Verbindungsoverhead mit der Datenbank und Aufwand um einen Query auszuführen.
Mir geht es persönlich tierisch auf den Sack, wenn ich mir immer 3x überlegen muss, welche Daten ich unbedingt aus der DB laden muss um nicht haufenweise Querys zu starten. Die Daten sollen sofort da sein, damit ich mit ihnen arbeiten kann.
gepostet vor 16 Jahre, 9 Monate von None
Zum Thema Speicherverbrauch... prüft bitte, ob der Compiler nicht automatisch die Variablen auf die 4 Byte Grenze legt.
gepostet vor 16 Jahre, 9 Monate von TheUndeadable
> prüft bitte, ob der Compiler nicht automatisch die Variablen auf die 4 Byte Grenze legt
Wenn dann der .Net-Jitter.
msdn.microsoft.com/library/deu/default.asp?url=/library/DEU/cpref/html/frlrfsystemruntimeinteropservicesstructlayoutattributeclasstopic.asp
.Net 2 sortiert die Struktur/Klasse ohne weitere Angaben so um, dass die Variablen auf 4 bzw 8-Byte-Grenzen liegen (32/64-Bit) und dass sowenig wie möglich Speicherplatz verloren geht. Dazu gibt es noch ein paar Ausnahmen für kleine Typen [byte, short].
Es wird ziemlich viel 'Magic' gemacht, aber viele boolean, byte und short-Werte teilen sich ein 4-Byte-Feld.
Ich persönlich speichere beim JFS alles in der Datenbank. Mein nächstes Projekt wird die kompletten Spielerdaten im Speicher halten. Nachrichten, lange Beschreibungen landen in einer Firebird-Datenbank. Die Spielerdaten werden alle X Minuten dupliziert und binär serialisiert geschrieben.
gepostet vor 16 Jahre, 9 Monate von Nuky
Mir kommt ja vor, dass du den Aufwand der Berechnung eines Kampfes usw. als größer einschätzt, als er ist. Könnte es nicht sein dass dein Ausgabesystem (php,asp,..) einfach wenn ein Kampf fehlt, diesen Kampf anfordern kann von deinem Programm und der dann ausgeführt wird? Prinzipiell halte ich diese Trennung sowieso für Wagemutig, was den Aufwand betrifft.
In was für Dimensionen bzgl. der Spieler denkst du hier?
gepostet vor 16 Jahre, 9 Monate von altertoby
@Drezil/Nuky:
jo klar is das Kampfystem ein eigener Thread, aber was bringt mir das?
Also zb. um herrauszufinden ob überhaupt ein Kampf startet brauch ich schonmal alle aktuellen Flottendaten (gut evt nicht alle aber die in einem bestimmten Bereich schon).
Dann beim Beginn des Kampfes muss ich von allen Schiffen die Daten hohlen inkulsive der eingebauten Module. Ect so geht das dann weiter.
Also sind das rund beim Beginn und dann beim Ende des Kampfes rund 20 Queries mit vielen Daten. Da die Berechnung des Kampfes rundenweise (aller 5min) geschehen soll und in den einzelnen Etappen zb auch logs erstellt werden sollen geht das mit nur bei Aufruf nur sehr sehr schwer.
@Agmemon/Klaus
Ich kann mich da eigentlich nur den Gegenargumenten von Klaus anschließen. Als einzigstes Problem seh ich halt auch die hohe RAM-Auslastung und evt wie man dann mehrere Server zusammen arbeiten lässt.
@TheUndeadable:
Ich weiß ja dass du auch .Net benutzt Also benutzt du um das im Cache zu halten eher List oder Dictonaries oder Hashtables oder ...
Und was mich noch interessiert: "binär serialisiert" dh? XML oder einfach mit BinaryFormater
gepostet vor 16 Jahre, 9 Monate von TBT
Hallo,
ich verfolge schon eine ganze Weile gespannt diesen Thread, und komme immer mehr zu dem Ergebnis, dass du eventuell einen anderen Ansatz verfolgen solltest.
Gerade im letzten Beitrag gehst du darauf ein, das du viele Daten benötigst. Meine Meinung nach, sind da viele Daten dabei, die sich selten ändern - z.B. "von allen Schiffen die Daten hohlen inklusive der eingebauten Module".
Warum packst du unter anderem diese Daten nicht einfach in einen schnellen Cache?
Ich selber bastel alles in PHP, und habe nun einen User übergreifenden Cache. Benötige ich Daten, wird zuerst der Cache gefragt, danach die Datenbank. Das reduziert die Anzahl der SQL Abfragen bei vielen Seiten auf 0. Alle Daten werden immer in die DB geschrieben, dadurch gibt es auch beim Serverabsturz keinen Datenverlust. Ändern sich Daten, wie die Ausstattung eines Schiffes, wird der Cache nur angewiesen, die entsprechenden Daten zu verwerfen. Beim nächsten Aufruf werden die aktuellen Daten wieder zwischengespeichert, bis sie wieder verworfen werden.
Auf diese Art und Weise stehen eventuell auch bei dir die meisten Daten bereits zur Verfügung, wenn dein Kampf gestartet wird.
TBT
gepostet vor 16 Jahre, 9 Monate von TheUndeadable
> Und was mich noch interessiert: "binär serialisiert" dh? XML oder einfach mit BinaryFormater
Ich nutze momentan den BinaryFormatter. Allerdings musst du da penibelst darauf achten, dass du die serialisierten Objekte korrekt erweiterst, so dass eine neue Version deines Programmes auch die alte Version deserialisieren kann. Ansonsten kann passieren, dass deine Datenbank für eine neue Programmversion unbrauchbar ist.
In der MSDN findest du darüber Information.
Ansonsten speicher ich zweifach:
Einmal als nativer Objektbaum. Also:
Game.Players[4].Towns[1].Buildings[3].IsActive, etc.
Und zweitens als Dictionary um schnell auf die Objekte zuzugreifen. Jedes Objekt, egal ob Spieler, Stadt, Gebäude hat eine eindeutige Id. In einem großen Dictionary werden alle Objekte gespeichert, so dass ich per (_DirectAccess[ID] as Building) direkt auf ein Gebäude zugreifen kann.
Nur musst du hier penibelst darauf aufpassen, dass Objekte nicht im Dictionary überleben, die du aus dem Objektbaum gelöscht hast und umgekehrt. Abstrahierung des Datenzugriffs ist hier das Stichwort.
Pro Spieler habe ich mir einen Richtwert von etwa 10 KB Daten überlegt. Dies macht bei für mich utopsischen 10.000 Spielern etwa 100 MB reine Nutzdaten. Damit kann ich persönlich leben.
Und wie ich schon schrieb: Lange Texte werden in einer echten Datenbank gespeichert.
Momentan schwanke ich zwischen Firebird und SQLite
www.firebirdsql.org/dotnetfirebird/blog/2005/02/embedded-firebird-and-microsoft-sql.html
weblogs.asp.net/jgalloway/archive/2006/04/12/442615.aspx
Aber sehr wahrscheinlich werde ich mich für Firebird entscheiden.
gepostet vor 16 Jahre, 9 Monate von altertoby
@TBT: das wäre auch ein interessanter Ansatzpunkt, wir haben uns trotzdem erstmal für das Speichern im Programm entschieden!!
@All: thx für eure bereichernden Aussagen!!
@TheUndeadable:
Wir haben uns jetzt doch gegen den BinaryFormatter entschieden (und für XML). Der Hauptgrund dafür war eigentlich, dass man falls evt. Änderungen an den Daten nötig sind das Notfalls noch per Hand machen kann...wäre dann zwar nicht die feine Englische Art aber falls es einfach mal nen Fehler im Code gibt und der irgendwas dummes mit den Daten anstellt kann man das so zur Not noch retten.
Und bei der Datenspeicherung haben wir auch eher die Listen genommen. Da man dort einfach nach Objekten suchen kann (also wenn man ein anderes Kriterium als die ID hat)
Atm sind die Daten um die 30kb groß (inklusive XML Markup) und das bei rund 20 Spielern. Es hält sich also atm noch sehr sehr im Rahmen!
Was mich aber am meisten verwundert hat, dass man dieses Umgestalten von SQL-DB auf jetzt Speicher-DB innerhalb eines Tages schaffen kann...wenn ich mir überlege dass wir für die bisherige Struktur der DB + Queries schreiben locker 2 Wochen gebraucht haben...das stimmt mich optimistisch, dass das Entwickeln jetzt um einen Haufen schneller geht!

Auf diese Diskussion antworten