Hallo,
ich mache mir gerade Gedanken über meine Highscore. Momentan wird sie beim ersten Seitenaufruf nach einer stunde aktualisiert. Da wir nur wenige user haben geht das ja noch, aber wenn wir mal über 1000 Spieler haben, dann gibt es eine lange ladezeit und die DB wird mit Inserts überflutet.
Funktionsweise:
Momentan wird einfach die Highscore Tabelle gelehrt, die neuen werte mit den Gebäuden, Forschung.... berechnet und dann per insert eingetragen.
ich habe gedacht, ich schreibe ein c++ prgramm, was dann per cron jede stunde aufgerufen wird(oder Daemon) und die Highscore aktualisiert.
Aber wie mache ich das jetzt am besten, tabelle leehren und dann per insert die neuen Punkte eintragen ODER
Per update die alten Punkte ändern?
Aber jetzt stellt sich bei mir die frage:
Wenn c++ gerade am updaten ist, dann sind die ladezeiten im game sicher höher, da mysql gerade ne menge insert's/updates macht?
mfg Roland
Highscore aktualisieren | C++ backend?
gepostet vor 18 Jahre, 5 Monate von planetenkiller
gepostet vor 18 Jahre, 5 Monate von Klaus
Du kannst auch alle Daten in ein Insert packen und hast am Ende nur noch 2 Queries. Bei vielen Daten hat MySQL natürlich viel zu tun, aber du kannst das Insert auch noch delayed machen, damit MySQL es auf einen Zeitpunkt verschiebt, wo es weniger zu tun hat. Solange kannst du auch die Anzeige der Highscore sperren.
gepostet vor 18 Jahre, 5 Monate von TheUndeadable
Bedenke, dass ein Großteil der Zeit für das Einfügen der Daten verloren geht. Da nutzt dir auch kein C++-Backend.
Die Datenbank ist der Flaschenhals und nicht das Backend. Ich nehme jetzt einfach an, dass du Funktionen wie sort, ksort oder usort genutzt hast. Dann dauert die Sortierung auch bei 1.000 Spielern in PHP nur Bruchteile eine Sekunde.
Ansonsten würde ich per Update die Punkte ändern und das ganze in einer Transaktion packen, dann schaffst du 10.000 Einträge in etwa einer Sekunde, auch in PHP.
Die Datenbank ist der Flaschenhals und nicht das Backend. Ich nehme jetzt einfach an, dass du Funktionen wie sort, ksort oder usort genutzt hast. Dann dauert die Sortierung auch bei 1.000 Spielern in PHP nur Bruchteile eine Sekunde.
Ansonsten würde ich per Update die Punkte ändern und das ganze in einer Transaktion packen, dann schaffst du 10.000 Einträge in etwa einer Sekunde, auch in PHP.
gepostet vor 18 Jahre, 5 Monate von MagicForrest
Wieso willst du das per Cronjob machen?
Das ganze wird, so wies sich anhört, ein kleines Tool, was auch nicht viele ressourcen benötigen wird - das kannst du doch 24/7 laufen lassen.
Ich würde das ganze per Update machen, bin mir aber nicht sicher ob das nicht etwas mehr Ressourcen fressen wird.
Du kannst das ganze aber auch direkt in die Datei der DB schreiben, und wenn die von anderen getrennt ist, sollte das nichtmal im Spiel auffallen dass das gerade hundert Abfragen usw sind.
Ist dafür aber um einiges aufwendiger zu schreiben.
Ansonsten kannst du das ganze ja nur ca. alle 60 Minuten machen, du kannst ja prüfen wieviele Spieler gerade online sind, wie hoch die Auslastung ist/etc., und dann würde ich sagen machst du das am besten in der Zeit wo am wenigsten User online sind.
Außer du musst das ganze wirklich genau jede Stunde machen, aber bei vielen Spielern wird das dann seeeehr Ressourcenfressend.
Du kannst aber die Highscores auch getrennt vom Spiel berechnen lassen.
Dann würde es nur die HS DB belasten.
Oder was auch eine Möglichkeit wäre (noch nicht probiert) wenn du das ganze nur 1x ausliest, auswertest und dann direkt in die Datei schreibst (also die alten Daten in der Datei überschreiben).
Wäre aber um einiges aufwendiger als wenn du das per MySQL machst - dafür aber bei mehreren tausend Spielern um einiges schneller als jede andere Möglichkeit.
Du könntest es aber auch auf die lange Art machen, und nur einzeln updaten/überschreiben.
Dann sind nicht zu viele inserts/etc auf einmal, aber die HS werden auch nur langsam geupdatet - was für Spieler sicherlich verwirrend wäre.
Im Grunde gibt es etliche Möglichkeiten...
Sind jetzt erstmal ein paar Gedanken die mir dazu eingefallen sind, werde vllt bei Zeit mal sowas schreiben und testen was wieviele Ressourcen benötigen würde, und was den Spielbetrieb am wenigsten stören würde.
//Edit: Hm.. waren 2 schneller als ich.. Aber ich denke man merkt nicht, dass ich C++ PHP vorziehe, oder?
Das ganze wird, so wies sich anhört, ein kleines Tool, was auch nicht viele ressourcen benötigen wird - das kannst du doch 24/7 laufen lassen.
Ich würde das ganze per Update machen, bin mir aber nicht sicher ob das nicht etwas mehr Ressourcen fressen wird.
Du kannst das ganze aber auch direkt in die Datei der DB schreiben, und wenn die von anderen getrennt ist, sollte das nichtmal im Spiel auffallen dass das gerade hundert Abfragen usw sind.
Ist dafür aber um einiges aufwendiger zu schreiben.
Ansonsten kannst du das ganze ja nur ca. alle 60 Minuten machen, du kannst ja prüfen wieviele Spieler gerade online sind, wie hoch die Auslastung ist/etc., und dann würde ich sagen machst du das am besten in der Zeit wo am wenigsten User online sind.
Außer du musst das ganze wirklich genau jede Stunde machen, aber bei vielen Spielern wird das dann seeeehr Ressourcenfressend.
Du kannst aber die Highscores auch getrennt vom Spiel berechnen lassen.
Dann würde es nur die HS DB belasten.
Oder was auch eine Möglichkeit wäre (noch nicht probiert) wenn du das ganze nur 1x ausliest, auswertest und dann direkt in die Datei schreibst (also die alten Daten in der Datei überschreiben).
Wäre aber um einiges aufwendiger als wenn du das per MySQL machst - dafür aber bei mehreren tausend Spielern um einiges schneller als jede andere Möglichkeit.
Du könntest es aber auch auf die lange Art machen, und nur einzeln updaten/überschreiben.
Dann sind nicht zu viele inserts/etc auf einmal, aber die HS werden auch nur langsam geupdatet - was für Spieler sicherlich verwirrend wäre.
Im Grunde gibt es etliche Möglichkeiten...
Sind jetzt erstmal ein paar Gedanken die mir dazu eingefallen sind, werde vllt bei Zeit mal sowas schreiben und testen was wieviele Ressourcen benötigen würde, und was den Spielbetrieb am wenigsten stören würde.
//Edit: Hm.. waren 2 schneller als ich.. Aber ich denke man merkt nicht, dass ich C++ PHP vorziehe, oder?
gepostet vor 18 Jahre, 5 Monate von planetenkiller
Wieso willst du das per Cronjob machen?
Als ich eine schleife in c++ ersetellt habe, ist die cpu auf 100% gestiegen
Ich kann ja in c++ ein sleep einfügen das 60 min wartet, oder so ändlich.
Bedenke, dass ein Großteil der Zeit für das Einfügen der Daten verloren geht. Da nutzt dir auch kein C++-Backend.
Ja das weiss ich.
das ganze in einer Transaktion packen
das ist eine gute idee, werde ich machen, ich nutze sowiso schon innodb.
ich möchte eben bestimmte sachen(Highscore updaten, Alte IGM's löschen, Bild der Karte erstellen, optimieren(db) befehl, ....) vom game trennen, damit nicht der user beim aufruf längere ladezeiten erhällt. Und da ich nicht ein Fan von php in der konsohle bin, mache ich es in c++.
ich danke euch für du guten ideen. ich glaube ich kriege es hin.
mfg planetenkiller
gepostet vor 18 Jahre, 5 Monate von Drezil
hmm..
1. ich seh das problem nicht so ganz .. der bottleneck ist ganz klar die db.. da nützt dir c++ nüscht.
2. wieso nimmt man für eine highscore innodb? die ist doch eh read-only .. und wenn die berechnet wird, dann kann man auch mit myisam per table-lock transaktionssicherheit gewährleisten ..
3. wenn man die daten zu jedem zeitpunkt rekonstruieren kann, kannste auch über ne heap-tabelle nachdenken - ist fixer .. braucht aber mehr ram ..
4. wieso überhaupt ne tabelle? ich berechne die ausgabe bei mir live in einer query.. aber auch nur, weil sich die sachen während kämpfen nahezu bei jedem aufruf ändern
1. ich seh das problem nicht so ganz .. der bottleneck ist ganz klar die db.. da nützt dir c++ nüscht.
2. wieso nimmt man für eine highscore innodb? die ist doch eh read-only .. und wenn die berechnet wird, dann kann man auch mit myisam per table-lock transaktionssicherheit gewährleisten ..
3. wenn man die daten zu jedem zeitpunkt rekonstruieren kann, kannste auch über ne heap-tabelle nachdenken - ist fixer .. braucht aber mehr ram ..
4. wieso überhaupt ne tabelle? ich berechne die ausgabe bei mir live in einer query.. aber auch nur, weil sich die sachen während kämpfen nahezu bei jedem aufruf ändern
gepostet vor 18 Jahre, 5 Monate von planetenkiller
1: das c++ mir nichts nützt weis ich, aber ich möchte es eben nicht abhängig von den user machen, die highscore soll im hintergrund aktualisiert werden. dann kann ich eben ein c++ daemon schreiben der die arbeiten druchfürt.
2: wenn man das mit table-lock macht ist aber die ganze Tabelle gesperrt. bei innodb kann ich die updates in einer transaktion machen und dan per comit werden die daten auf einmal wirksam. ich könnte ja noch machen das all 2 sec 100 update 's ausgefürt werden ob es ein paar sekunden oder ein paar minuten dauert ist eigenlich egal.
3: heap ist auch nicht schlecht, man müste nur aufpassen, das wenn der server neustartet, die tabelle dann lehr ist.
4: bei mir ändern sich die punkte nicht so häufig
2: wenn man das mit table-lock macht ist aber die ganze Tabelle gesperrt. bei innodb kann ich die updates in einer transaktion machen und dan per comit werden die daten auf einmal wirksam. ich könnte ja noch machen das all 2 sec 100 update 's ausgefürt werden ob es ein paar sekunden oder ein paar minuten dauert ist eigenlich egal.
3: heap ist auch nicht schlecht, man müste nur aufpassen, das wenn der server neustartet, die tabelle dann lehr ist.
4: bei mir ändern sich die punkte nicht so häufig
gepostet vor 18 Jahre, 5 Monate von abuzeus
Eine einfachere Variante wäre, den Flaschenhals gar nicht erst entstehen zu lassen. Wenn sich die Punkte eh nicht allzu oft ändern, dann kannst du auch einfach die Punkte für den betreffende User direkt per php verändern, wenn er Punkte dazubekommt oder verliert.
Damit ahst du die last in Minimalstdosen auf die Stunde verteilt und umgehst das Problem. Du kannst dann immer noch nachts um3 oder Samstag abend um 23 Uhr einen Kontrolldurchlauf machen, dass die Puntke noch einmal selbstständig berechnet, falls du deinen Programmierkünsten nicht traust. Da dürfte die Last auch keinen stören.
Damit ahst du die last in Minimalstdosen auf die Stunde verteilt und umgehst das Problem. Du kannst dann immer noch nachts um3 oder Samstag abend um 23 Uhr einen Kontrolldurchlauf machen, dass die Puntke noch einmal selbstständig berechnet, falls du deinen Programmierkünsten nicht traust. Da dürfte die Last auch keinen stören.
gepostet vor 18 Jahre, 5 Monate von leitstelle
Der Version würde ich auch zustimmen!
Einfach bei Fertigstellung auch Punkte aktualisieren, so entzerrt sich der Datenbankzugriff und Punkte sind aktuell^^
Einfach bei Fertigstellung auch Punkte aktualisieren, so entzerrt sich der Datenbankzugriff und Punkte sind aktuell^^
gepostet vor 18 Jahre, 5 Monate von KoMtuR
Man könnte auch mal was ganz anderes probieren. Man könnte jedes mal ne Stored Procedure in der DB verwenden, welche die Punkte aktuell hält. Somit nutzt man dann nicht mehr die update-Methode, um punktrelevante Sachen zu aktualisieren, sondern halt die SP der DB. Ich spreche hier nicht explizit von MySql. Es gibt genug DB-Engines, die diese Teile unterstützten. Somit brauchste dich garnicht mit den Punkten rumzuschlagen und vorallem was sollte es wohl nochmal ein wenig Geschwindigkeit dazu geben, weil die Anweisungen ja in der DB drin stehen und nicht von aussen drauf zugreifen.
gepostet vor 18 Jahre, 5 Monate von planetenkiller
geanu, die idee von abuzeus ist gut, das werde ich machen.
an Stored Procedure habe ich auch schon gedacht, aber das kenne ich leider noch zu wenig.
an Stored Procedure habe ich auch schon gedacht, aber das kenne ich leider noch zu wenig.
gepostet vor 18 Jahre, 5 Monate von unverbraucht
(sorry dass ich nen älteren Thread aufwärm)
Aber ist das Problem nicht eher der Rang als die Punkte selbst? Wenn ein Spieler ein Gebäude fertigstellt, könnte man ja die Punkte direkt aufaddieren. Aber wenn man nur die Punkte kennt, kann man ja nicht auf den Rang schliessen, ausser man liest sich per SELECT alle Spieler sortiert nach Punkten aus - nicht sonderlich schnell, wenn man von den 30,000 Spielern nur Rang 50-60 ausgeben will.
Ich hab dafür eine Zwischentabelle, die Spieler-ID auf den Rang mappt, und die zeitgesteuert alle Spieler durchläuft und den Rang abspeichert. Dabei wird die ganze Table gelockt und dann ein Massen-Insert gemacht. Braucht für 1000 Testspieler weniger als eine halbe Sekunde. Möglich wäre hier auch ein REPLACE...SELECT, damit die DB sich direkt um alles kümmert.
Aber ist das Problem nicht eher der Rang als die Punkte selbst? Wenn ein Spieler ein Gebäude fertigstellt, könnte man ja die Punkte direkt aufaddieren. Aber wenn man nur die Punkte kennt, kann man ja nicht auf den Rang schliessen, ausser man liest sich per SELECT alle Spieler sortiert nach Punkten aus - nicht sonderlich schnell, wenn man von den 30,000 Spielern nur Rang 50-60 ausgeben will.
Ich hab dafür eine Zwischentabelle, die Spieler-ID auf den Rang mappt, und die zeitgesteuert alle Spieler durchläuft und den Rang abspeichert. Dabei wird die ganze Table gelockt und dann ein Massen-Insert gemacht. Braucht für 1000 Testspieler weniger als eine halbe Sekunde. Möglich wäre hier auch ein REPLACE...SELECT, damit die DB sich direkt um alles kümmert.
gepostet vor 18 Jahre, 4 Monate von Benny G-Punkt
hmm, warum berechnest du die punkte nicht on-the-fly wenn sie sich ändern?
also z.B.: ein user baut ein gebäude dass 100 Punkte einbringt.
Du berechnest die neue Punktzahl.
Du schaust auf welchem Platz der User nun landet
Nun musst du nur die Plätze die zwischen alter und neuer Position liegen updaten.
Wenn es 10 User gibt und ein User von Position 3 auf position 5 fällt ändern sich auch nur die Positionen der user auf Position 3-5.
Dass wäre dann ein Updatestatement:
UPDATE highscore SET position = position-1 WHERE position <= neuePos AND Position > altePos
} else if (userSteigtAb) {
UPDATE highscore SET position = position+1 WHERE position < altePos AND Position >= neuePos
}
Dass minimiert die anzahl der Updatestatements auf die wahrscheinlich kleinstmögliche zahl.
also z.B.: ein user baut ein gebäude dass 100 Punkte einbringt.
Du berechnest die neue Punktzahl.
Du schaust auf welchem Platz der User nun landet
Nun musst du nur die Plätze die zwischen alter und neuer Position liegen updaten.
Wenn es 10 User gibt und ein User von Position 3 auf position 5 fällt ändern sich auch nur die Positionen der user auf Position 3-5.
Dass wäre dann ein Updatestatement:
if(UserSteigtAuf) {
UPDATE highscore SET position = position-1 WHERE position <= neuePos AND Position > altePos
} else if (userSteigtAb) {
UPDATE highscore SET position = position+1 WHERE position < altePos AND Position >= neuePos
}
Dass minimiert die anzahl der Updatestatements auf die wahrscheinlich kleinstmögliche zahl.