Automatch / mise en file d'attente des joueurs

8

J'utilise Node.js et Redis. J'essaie de trouver un moyen fiable d'automatiser les joueurs. Il y a un serveur correspondant, puis plusieurs serveurs de jeu configurés.

Voici ce que je dois faire:

  1. Le joueur envoie une demande de jointure avec le type de jeu (petit / moyen, etc.)
  2. Le serveur correspondant ajoute un joueur au type de jeu actuel qui attend les joueurs
  3. Le serveur de jeu envoie au joueur l'ID de jeu

Actuellement, je l'ai implémenté comme suit:

  1. Le serveur correspondant écoute le jeu: file d'attente: petite à l'aide de BRPOP
  2. Vérifie si game: queue: small: id = id existe
  3. Vérifie si le jeu: id: la longueur des utilisateurs est <= 6 (max joueurs)
  4. Ajoute un joueur au jeu: id: liste des utilisateurs si c'est le cas
  5. Si la durée de la partie est désormais de 6, elle supprime la partie: file d'attente: petite: id

Si le serveur correspondant trouve game: queue: small: id est manquant, il procède comme suit:

  1. Jeu INCR: nextGameId
  2. Définit le jeu: file d'attente: petite: id à l'ID généré précédemment
  3. Ajoute l'ID de jeu au jeu: file d'attente: attente

Les serveurs de jeux attendent d'utiliser BRPOP pour de nouveaux jeux. Lorsqu'ils en obtiennent un, ils attendent que le jeu compte au moins 2 utilisateurs, puis démarrent un chronomètre. S'ils ne se remplissent pas pendant ce temps, ils commencent par les utilisateurs qu'ils ont et suppriment ensuite le jeu: file d'attente: petit: id (forçant ainsi le marieur à demander un nouveau jeu).

Bien que ma méthode fonctionne, je ne suis pas convaincu qu'elle fonctionnera bien en production et elle semble très compliquée. Je peux voir le potentiel des problèmes suivants:

  • Le serveur de jeu se bloque après avoir accepté l'ID de jeu de la liste d'attente, ce qui entraîne l'ajout d'utilisateurs au jeu: id: utilisateurs mais rien ne se passe avec eux (le crash lui-même n'est pas un problème, mais les utilisateurs continuent d'être ajoutés à cette file d'attente de jeux est )
  • Si un utilisateur se déconnecte et que le jeu n'a pas commencé, le serveur de jeu supprimera l'utilisateur de la liste game: id: users. Pendant qu'il est en train de le faire, le serveur de mise en relation pourrait ajouter un utilisateur à la liste et penser que le jeu est complet, le supprimant ainsi de la file d'attente.

Mes pensées initiales ont été de passer à une seule file d'attente d'utilisateurs attendant un type de jeu. Cependant, cela pose d'autres problèmes:

  • Si le serveur auquel les utilisateurs se connectent se bloque, il ne supprimera pas l'utilisateur de la file d'attente, laissant ainsi cet utilisateur à entrer dans un jeu lorsqu'il n'existe pas. Je pourrais utiliser des ensembles triés pour stocker l'heure de la demande et faire interroger le client jusqu'à ce qu'il reçoive un ID de jeu, mais cela signifierait que je n'ai aucune idée du temps que ce client a attendu et donc je ne sais pas s'il faut démarrer le jeu. avec moins d'utilisateurs.
  • Sans mettre les utilisateurs dans un jeu, ils n'ont pas la possibilité de voir ce que les utilisateurs ont rejoint, ni la possibilité de discuter avec les utilisateurs qui attendent (car cela nécessite un ID de jeu).

Rien de la façon dont j'ai mis cela en place ne me semble juste, alors j'espérais que quelqu'un pourrait offrir de meilleures suggestions. J'ai vraiment besoin de garder les serveurs de jeu et les serveurs de matchmaking séparés, afin de les développer au besoin.

Chris Evans
la source
Le problème de base de données que j'ai résolu ici: stackoverflow.com/questions/15172556/…
Chris Evans
Dans Vérifie si le jeu: file d'attente: petit: id = id existe , comment obtenez-vous l'ID?
Rayon

Réponses:

1

Votre première erreur est d'utiliser une base de données pour une file d'attente en direct, ces données sont beaucoup mieux stockées dans la mémoire de processus dans le processus de mise en correspondance. Laissez les processus communiquer directement entre eux. Ensuite, il vous est également à peu près imposé qu'il incombe au serveur de matchmaking de retirer les joueurs de la file d'attente lorsqu'ils sont mis dans un jeu, comme il se doit.

Plus généralement sur le matchmaking, retardez les décisions concernant les correspondances exactes à faire jusqu'au début du jeu.Si vous avez 3 joueurs qui correspondent à un jeu à 4 joueurs, ne décidez pas qu'ils doivent jouer à ce type de jeu avant qu'il n'y ait également un 4ème joueur, il pourrait prendre du temps pour que ce joueur arrive, et certains d'entre eux pourraient cesser d'attendre entre-temps. Une implémentation décente pour cela est d'avoir une file d'attente pour chaque type de jeu et de placer chaque joueur dans toutes les files d'attente correspondant à leur demande, puis lorsqu'une file d'attente est pleine, démarrez le jeu et supprimez les joueurs impliqués de toutes leurs files d'attente.

aaaaaaaaaaaa
la source
J'utilisais Redis comme gère bien les files d'attente. Au départ, je gérais le matchmaking au sein du serveur lui-même et cela a très bien fonctionné, mais j'ai trouvé deux problèmes avec cette approche: je ne pouvais pas trouver un moyen de l'étendre et, deuxièmement, comment le serveur demandait-il un nouveau jeu pour démarrer sur un autre serveur. Cela pourrait leur envoyer un message à tous, mais la charge ne serait pas équilibrée?
Chris Evans
1
@ChrisEvans Vous ne devriez pas trop vous soucier de la mise à l'échelle, un simple processus de matchmaking peut gérer des milliers d'initiations de jeu par seconde. Si seulement vous le codez bien, vous n'aurez pas besoin de la mise en correspondance pour vous adapter à plusieurs processus, même si vous obtenez des millions de clients. En ce qui concerne l'équilibrage de la charge sur les serveurs de jeux, une approche à tour de rôle simple où chaque serveur de jeux obtient un nouveau jeu à son tour est raisonnablement efficace si les serveurs sont généralement capables de gérer un grand nombre de jeux chacun. Sinon, vous pouvez demander périodiquement aux serveurs de jeu à quel point ils sont occupés, cela ne doit pas se produire une fois par nouveau jeu.
aaaaaaaaaaaa