Spielprotokollformat für MMO-Server


12

Ein Protokoll von Spielereignissen (im Gegensatz zu Fehler- / Debug-Protokollen) für einen gesamten Cluster / Shard ist sehr nützlich für ein kommerzielles MMO, das sich in einer Live-Produktionsumgebung befindet und wichtige Unterstützung für den Kundenservice und die Mittel für die Verlaufsanalyse bietet.

Das Projekt, an dem ich gerade arbeite, verwendet eine relationale Datenbank, um alle Spielereignisprotokolle zu speichern, und obwohl diese Methode einwandfrei funktioniert, scheint es mir, dass die schreibgeschützte, chronologische Natur der Protokolle ein effizienteres Speicherformat ermöglichen würde .

Ich bin mir jedoch nicht sicher, wo ich anfangen soll, benutzerdefinierte binäre Protokollformate zu erstellen. Welche Erfahrungen haben Sie mit der Erstellung von benutzerdefinierten Protokollformaten oder empfohlenen Artikeln zu diesem Thema gemacht?

Antworten:


7

In Stendhal haben wir das Leistungsproblem behoben, indem wir Spielereignisse zu einer Warteschlange hinzugefügt und diese dann asynchron im Hintergrund verarbeitet haben .

In unserem Fall handelt es sich bei den Ereignissen nicht nur um Aufzeichnungen, sondern um Objekte, die ein wenig Logik besitzen, da in einigen Fällen zwei Einfügungen mit einer Verknüpfung zwischen ihnen erforderlich sind. Wenn zum Beispiel ein Gegenstand zum ersten Mal im Spiel behandelt wird, muss er zuerst in die Gegenstands-Tabelle eingefügt werden, bevor ein Gegenstands-Ereignis protokolliert werden kann.

Das Schreiben des Protokolls ist jedoch nur eine Seite des Problems:

Welche Fragen möchten Sie mit den Protokollen beantworten?

Es ist einfach, das gesamte Protokoll in chronologischer Reihenfolge zu lesen. oder um es für einen Spieler zu filtern.

Aber es könnte Fragen geben wie:

  • Welche Gegenstände hat Anton auf den Boden gelegt, die Beth gestern abgeholt hat? Welcher Spieler besitzt sie jetzt? (Anton beschwerte sich über den Diebstahl seines Gegenstands)
  • Wie viel Zeit braucht ein durchschnittlicher Spieler, um Level 100 zu erreichen? Welche Spieler waren deutlich schneller? nur für erste zeichen?
  • Gibt es Spieler, die mit riesigen Mengen an Spielgeld umgehen? An welche Spieler wird es weitergegeben? Ohne etwas Wertvolles?
  • Können schwache Spieler starke Kreaturen töten, die sie legal nicht töten sollten?
  • ...

In Stendhal verwenden wir eine relationale Datenbank für Spielprotokolle, da dies der einfachste Weg ist, um performante Ad-hoc-Abfragen zu ermöglichen. Wenn Sie ein benutzerdefiniertes Protokollformat verwenden, müssen Sie grundsätzlich alle diese Abfragen codieren, wenn dies erforderlich ist. Und das mit ausreichender Leistung zu tun, wird ziemlich schwierig.

Unser gameEvents-Tisch hat 51.429.139 Zeilen (letztes Jahr) und wir haben einen speziellen Itemlog-Tisch mit 60.360.657 Zeilen (alle Zeiten) für 15.893.831 Artikel.


Wie schnell wird in Ihrer Datenbank gesucht? Ich habe eine ähnliche Datenbank mit Protokollen und wir haben ungefähr 100.000.000 Zeilen nach drei Monaten. Wir verwenden MySQL als Speicher und die Leistung ist schlecht. Einfache Abfrage, die alle Aktionen eines Spielers auflistet (nur 20.000), dauert oft länger als 60 Sekunden.
Balon

1
Einfache Abfragen für Indexspalten werden sofort ausgeführt. Komplexe Abfragen können einige Zeit in Anspruch nehmen, 60 Sekunden dauern, aber sie sind sehr selten. Wir haben die Tabelle sehr stark indiziert und die Strafe beim Einfügen durch asynchrone Ausführung ausgeglichen.
Hendrik Brummermann

Hmmm, ich denke mein Problem ist, dass die Ergebnismenge ziemlich groß ist, oft zwischen 3000 und 150000 Datensätze für einen Spieler. Dies kann der Grund sein, warum es so lange dauert, weil es für kleine Ergebnismengen sehr schnell funktioniert.
Balon

4

Was meinen Sie mit Effizienz? Unabhängig davon, ob es sich um die Größe der Festplatte oder die Abfragegeschwindigkeit handelt, wird eine relationale Datenbank mit ziemlicher Sicherheit Ihr proprietäres Binärformat übertreffen oder diesem entsprechen und viel einfacher und flexibler zu verwenden sein.

In jeder Tabelle, die Sie in einer relationalen Datenbank verwenden, können Sie genau byteweise angeben, wie viel Speicherplatz pro Zeile zulässig ist. Wenn Sie keinen Klartext protokollieren - und "Spielereignisse protokollieren (im Gegensatz zu Fehler- / Debug-Protokollen)" impliziert, dass Sie dies nicht tun oder zumindest nicht müssen - dann ist der Feldansatz mit fester Breite von a relationale Datenbanken sind in Bezug auf den Speicherplatz nahezu optimal, was sie in erster Linie ziemlich schnell macht. Darüber hinaus sind relationale Datenbanken sehr praktisch, wenn es darum geht, Indizes für einen sehr schnellen Zugriff zu erstellen und Abfragen zu optimieren, um das Beste aus ihnen herauszuholen.

Also würde ich empfehlen, bei dem zu bleiben, was du hast.


Danke für die Antwort (und danke an die anderen, die unten Antworten eingereicht haben)! Je mehr ich darüber nachdenke, desto mehr scheint ein RDBMS für diese bestimmte Art der Protokollierung geeignet zu sein. Es wäre nicht allzu schwierig, ein benutzerdefiniertes Protokollformat zu entwerfen, das für grundlegende Suchanfragen gut indiziert ist. Angesichts der komplizierten Abfragen, die häufig von CSRs und Spielanalysen verwendet werden, ist jedoch ein allgemeinerer Ansatz erforderlich Ein etabliertes Produkt wird in den meisten Fällen eine Outperformance erzielen.
Charles Ellis

Die Einrichtung eines benutzerdefinierten Ereignisprotokolls wäre praktisch für die streng chronologische Wiedergabe von FPS-Demoaufzeichnungen, aber das ist ein ganz anderes Problem, das gelöst werden muss. Hat jemand Erfahrung mit der Entwicklung von Demoaufnahmen für Client-Server-Spiele mit mehreren Spielern?
Charles Ellis

Abhängig von Ihrem serverseitigen Logikverarbeitungsmodell kann es möglich sein, nur jede Eingabe zu speichern, die mit der Ankunftszeit auf dem Server versehen ist und die wiedergegeben werden kann. Das Problem tritt in der Regel bei der Wiedergabe auf, da Sie jede einzelne Eingabe wiederholen und andere Faktoren modellieren müssen (z. B. zufällige Startwerte, implizite Eingaben, z. B. Dinge, die sich aufgrund der Latenz ändern usw.). Hier gibt es jedoch kein einheitliches System - es hängt davon ab, wie Ihr Server funktioniert.
Kylotan

3

Es ist wahr, dass Sie wahrscheinlich ein paar Bytes mit einem benutzerdefinierten Format oder einfach nur gezipptem Text sparen könnten. Die Speicherung ist billig, sodass es sich nicht mehr lohnt, sie zu optimieren. Wichtiger ist, sich mit Dingen wie E / A-Pufferung und Abfrage zu befassen, die ein handelsüblicher SQL-Server wahrscheinlich recht gut kann. Wenn es für Sie an diesen Fronten funktioniert, würde ich damit rennen. Wir haben unseren eigenen Pufferprotokollserver geschrieben, der in benutzerdefinierte Dateien schreibt und dann über ein separates Parserprogramm verfügt, um sie für Abfragen in eine Datenbank zu lesen. Ich würde es nicht empfehlen.


0

Relationale Datenbanken werden heutzutage als ineffizient eingestuft. Wenn Sie jedoch die Art von Protokollen speichern, über die Sie sprechen, benötigen Sie keine wirkliche Effizienz, da das Spiel oder seine Benutzer nicht ständig auf sie zugreifen können - nur Ihr Team wird sie benötigen um die Daten zu lesen.

"Effizienz" spielt also keine Rolle. Vielmehr geht es darum, die Daten so zu ordnen, dass auf einfache Weise erzählt werden kann, was die Benutzer im Spiel tun. Ihre Entwickler müssen diese Daten in der Regel konsumieren und in einer für Analysten leicht lesbaren Oberfläche anzeigen, und Analysten müssen manchmal die Daten abfragen, um das Nutzerverhalten zu untersuchen. Wenn Spieler beispielsweise einen bestimmten Artikel vor einem Update kaufen, diesen aber nach einem Update nicht mehr kaufen, kann ein Analyst bestimmte Abfragen durchführen, um herauszufinden, warum Benutzer ihn nicht mehr kaufen. Am besten verwenden sie eine Standard-Abfragesprache, die gut dokumentiert ist. Wenn sie diese Abfragen in ein benutzerdefiniertes Binärformat umwandeln müssen, werden ihre Jobs VIEL schwieriger.

Im Allgemeinen sehen Spielevents so aus (dies ist insbesondere das Format von DeltaDNA)

{
 "eventName":"specific event code – eg. gameStarted",
 "userID":"ABCD1-4321a879b185fcb9c6ca27abc5387e914",
 "sessionID":"4879bf37-8566-46ce-9f3b-bd18d6ac614e",
 "eventTimestamp":"yyyy-mm-dd hh:mm:ss.SSS",
 "eventParams":
  {
   "platform":"WEB",
   "param1":"stringParam",
   "param2":true,
   "param3":1234,
   "param4":["a","b","c"]
  },
}

Das Ereignis enthält normalerweise einen Ereignisnamen, eine Benutzer-ID, eine Sitzungs-ID, einen Zeitstempel und Parameter, mit denen Sie alle Daten aufzeichnen können, die Sie für die Aufzeichnung des Ereignisses als nützlich erachten. Und meiner Erfahrung nach eignen sich relationale Datenbankformate am besten, um eine solche Struktur aufzuzeichnen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.