Automatch / Queuing-Spieler

8

Ich benutze Node.js und Redis. Ich versuche, einen zuverlässigen Weg zu finden, um Spieler automatisch abzufangen. Es gibt einen passenden Server und dann mehrere Spieleserver.

Folgendes muss geschehen sein:

  1. Der Spieler sendet eine Beitrittsanfrage mit Spieltyp (klein / mittel usw.)
  2. Der passende Server fügt den Spieler dem aktuellen Spieltyp hinzu, der auf die Spieler wartet
  3. Der Spieleserver sendet dem Spieler die Spiel-ID

Derzeit habe ich dies wie folgt implementiert:

  1. Passender Server hört auf Spiel: Warteschlange: klein mit BRPOP
  2. Überprüft, ob game: queue: small: id = id vorhanden ist
  3. Überprüft, ob das Spiel: id: Benutzerlänge <= 6 ist (max. Spieler)
  4. Fügt Spieler zum Spiel hinzu: id: Benutzerliste, falls vorhanden
  5. Wenn die Spiellänge jetzt 6 ist, wird game: queue: small: id entfernt

Wenn der übereinstimmende Server das Spiel findet: queue: small: id fehlt, geschieht dies wie folgt:

  1. INCR-Spiel: nextGameId
  2. Setzt game: queue: small: id auf die zuvor generierte ID
  3. Fügt die Spiel-ID zum Spiel hinzu: Warteschlange: Warten

Die Spieleserver warten mit BRPOP auf neue Spiele. Wenn sie einen bekommen, warten sie, bis das Spiel mindestens 2 Benutzer hat, und starten dann einen Timer. Wenn sie diese Zeit nicht ausfüllen, beginnen sie mit den Benutzern, die sie haben, und entfernen anschließend game: queue: small: id (wodurch der Matchmaker gezwungen wird, ein neues Spiel anzufordern).

Während meine Methode funktioniert, bin ich nicht davon überzeugt, dass sie in der Produktion gut funktionieren wird, und sie scheint sehr kompliziert zu sein. Ich kann das Potenzial für die folgenden Probleme erkennen:

  • Der Spieleserver stürzt ab, nachdem die Spiel-ID von der Warteliste akzeptiert wurde, was dazu führt, dass Benutzer zum Spiel hinzugefügt werden: id: Benutzer, aber nichts passiert mit ihnen (der Absturz selbst ist kein Problem, aber Benutzer, die weiterhin zu dieser Spielewarteschlange hinzugefügt werden, sind )
  • Wenn ein Benutzer die Verbindung trennt und das Spiel noch nicht gestartet wurde, entfernt der Spieleserver den Benutzer aus der Liste game: id: users. Währenddessen könnte der Matchmaking-Server einen Benutzer zur Liste hinzufügen und denken, dass das Spiel voll ist, wodurch er aus der Warteschlange entfernt wird.

Meine ersten Gedanken waren, zu einer einzigen Warteschlange von Benutzern zu wechseln, die auf einen Spieltyp warten. Dies wirft jedoch weitere Probleme auf:

  • Wenn der Server, zu dem die Benutzer eine Verbindung herstellen, abstürzt, wird der Benutzer nicht aus der Warteschlange entfernt, sodass dieser Benutzer in ein Spiel aufgenommen werden kann, wenn er nicht vorhanden ist. Ich könnte sortierte Sätze verwenden, um die Zeit der Anfrage zu speichern und die Client-Umfrage durchzuführen, bis eine Spiel-ID zurückgegeben wird. Dies würde jedoch bedeuten, dass ich keine Ahnung habe, wie lange dieser Client gewartet hat und daher nicht weiß, ob ich das Spiel starten soll mit weniger Benutzern.
  • Ohne die Benutzer in ein Spiel einzubeziehen, können sie weder sehen, was Benutzer beigetreten sind, noch mit den wartenden Benutzern chatten (da hierfür eine Spiel-ID erforderlich ist).

Die Art und Weise, wie ich dies eingerichtet habe, fühlt sich nicht richtig an, also hoffte ich, dass jemand in der Lage sein könnte, bessere Vorschläge zu machen. Ich muss die Spielserver und die Matchmaking-Server wirklich getrennt halten, um sie nach Bedarf zu vergrößern.

Chris Evans
quelle
Das Datenbankproblem, das ich hier behoben habe: stackoverflow.com/questions/15172556/…
Chris Evans
In Überprüft, ob game: queue: small: id = id vorhanden ist. Wie erhalten Sie die ID?
Rayon

Antworten:

1

Ihr erster und größter Fehler besteht darin, eine Datenbank für eine Live-Warteschlange zu verwenden. Diese Daten sind im Matchmaking-Prozess viel besser im Prozessspeicher gespeichert. Lassen Sie die Prozesse direkt miteinander kommunizieren. Dann ist es auch ziemlich erzwungen, dass es in der alleinigen Verantwortung des Matchmaking-Servers liegt, Spieler aus der Warteschlange zu entfernen, wenn sie in ein Spiel aufgenommen werden, wie es sein sollte.

Wenn Sie 3 Spieler haben, die zu einem 4-Spieler-Spiel passen, entscheiden Sie nicht, dass sie diese Art von Spiel spielen müssen, bevor es Matchmaking gibt Auch ein 4. Spieler, es könnte lange dauern, bis dieser Spieler ankommt, und einige von ihnen könnten in der Zwischenzeit aufhören zu warten. Eine vernünftige Implementierung hierfür besteht darin, eine Warteschlange für jeden Spieltyp zu haben und jeden Spieler in alle Warteschlangen zu stellen, die seiner Anforderung entsprechen. Wenn eine Warteschlange voll ist, starten Sie das Spiel und entfernen Sie die beteiligten Spieler aus allen Warteschlangen.

aaaaaaaaaaaa
quelle
Ich habe Redis gut als Warteschlangen verwendet. Ich habe das Matchmaking ursprünglich auf dem Server selbst verwaltet und es hat sehr gut funktioniert, aber ich habe zwei Probleme mit diesem Ansatz festgestellt: Ich konnte keinen Weg finden, es zu skalieren, und zweitens, wie fordert der Server ein neues Spiel an, um auf einem anderen Server zu starten. Es könnte eine Nachricht an alle senden, aber dann wäre die Last nicht ausgeglichen?
Chris Evans
1
@ChrisEvans Sie sollten sich nicht zu viele Gedanken über die Skalierung machen. Ein einfacher Matchmaking-Prozess kann Tausende von Spielinitiierungen pro Sekunde verarbeiten. Wenn Sie es nur gut codieren, müssen Sie das Matchmaking nicht auf mehrere Prozesse skalieren, selbst wenn Sie Millionen von Kunden gewinnen. Um die Last auf den Spielservern auszugleichen, ist ein einfacher Round-Robin-Ansatz, bei dem jeder Spielserver wiederum ein neues Spiel erhält, angemessen effektiv, wenn die Server im Allgemeinen in der Lage sind, jeweils eine große Anzahl von Spielen zu verarbeiten. Andernfalls können Sie die Spielserver regelmäßig fragen, wie beschäftigt sie sind. Dies muss nicht einmal pro neuem Spiel geschehen.
aaaaaaaaaaaa