Automatch / jogadores na fila

8

Estou usando o Node.js e o Redis. Estou tentando encontrar uma maneira confiável de automatch jogadores. Há um servidor correspondente e vários servidores de jogos configurados.

A seguir, é o que eu preciso que aconteça:

  1. O jogador envia uma solicitação de ingresso com o tipo de jogo (pequeno / médio etc.)
  2. O servidor correspondente adiciona o jogador ao tipo de jogo atual que está aguardando jogadores
  3. O servidor do jogo envia ao jogador o ID do jogo

Atualmente eu implementei isso da seguinte maneira:

  1. O servidor correspondente ouve o jogo: fila: pequeno usando o BRPOP
  2. Verifica se existe jogo: fila: pequeno: id = id
  3. Verifica se game: id: comprimento dos usuários é <= 6 (máximo de jogadores)
  4. Adiciona jogador ao jogo: id: lista de usuários, se for
  5. Se a duração do jogo for agora 6, ele removerá jogo: fila: pequeno: id

Se o servidor correspondente encontrar game: fila: small: id está ausente, faça o seguinte:

  1. Jogo INCR: nextGameId
  2. Define game: fila: small: id para o ID gerado anteriormente
  3. Adiciona o ID do jogo ao jogo: fila: aguardando

Os servidores de jogos esperam usando o BRPOP para novos jogos. Quando eles obtêm um, eles esperam até o jogo ter no mínimo 2 usuários e iniciam um cronômetro. Se eles não preencherem nesse período, eles começarão com os usuários que eles têm e, posteriormente, removerão game: fila: small: id (forçando assim o casamenteiro a solicitar um novo jogo).

Enquanto meu método está funcionando, não estou convencido de que funcione bem na produção e parece muito complicado. Eu posso ver o potencial para os seguintes problemas:

  • O servidor do jogo trava depois de aceitar o ID do jogo na lista de espera, resultando na adição de usuários ao jogo: id: usuários, mas nada acontece com eles (a falha em si não é um problema, mas os usuários que continuam sendo adicionados à fila de jogos são: )
  • Se um usuário desconectar e o jogo não iniciar, o servidor do jogo removerá o usuário da lista game: id: users. Enquanto isso, o servidor de matchmaking pode adicionar um usuário à lista e pensar que o jogo está cheio, removendo-o da fila.

Meu pensamento inicial era mudar para uma única fila de usuários esperando por um tipo de jogo. No entanto, isso apresenta outras questões:

  • Se o servidor ao qual os usuários se conectam falhar, ele não removerá o usuário da fila, deixando esse usuário para entrar em um jogo quando eles não existirem. Eu poderia usar conjuntos classificados para armazenar o tempo da solicitação e fazer com que a pesquisa do cliente até que o ID do jogo seja retornado, mas isso significa que não tenho idéia de quanto tempo o cliente esperou e, portanto, não sei se o jogo deve ser iniciado. com menos usuários.
  • Sem colocar os usuários em um jogo, eles não têm a capacidade de ver o que os usuários entraram, nem a capacidade de conversar com os usuários que estão aguardando (pois isso requer um ID do jogo).

Nenhuma das formas como eu configurei isso parece certa, então eu esperava que alguém pudesse oferecer algumas sugestões melhores. Eu realmente preciso manter os servidores de jogos e os servidores de partidas separados, a fim de expandi-los conforme necessário.

Chris Evans
fonte
A questão de banco de dados Eu resolvi aqui: stackoverflow.com/questions/15172556/...
Chris Evans
Em Verifica se jogo: fila: pequeno: id = id existe , como você obtém o ID?
Rayon

Respostas:

1

Seu primeiro e principal erro é usar um banco de dados para uma fila ao vivo; esses dados são muito melhores armazenados na memória do processo no processo de criação de partidas. Deixe os processos se comunicarem diretamente. Também é bastante forçado a você que é de responsabilidade exclusiva do servidor de matchmaking remover jogadores da fila quando eles são colocados em um jogo, como deveria ser.

De um modo mais geral sobre matchmaking, adie as decisões de quais partidas exatas serão feitas até o ponto em que o jogo começa; se você tiver 3 jogadores que se encaixam em um jogo de 4 jogadores, não decida que eles precisam jogar esse tipo de jogo antes que haja também como quarto jogador, pode demorar muito tempo para chegar, e alguns deles podem parar de esperar enquanto isso. Uma implementação decente para isso é ter uma fila para cada tipo de jogo e colocar cada jogador em todas as filas correspondentes à sua solicitação; quando uma fila estiver cheia, inicie o jogo e remova os jogadores envolvidos de todas as suas filas.

aaaaaaaaaaaa
fonte
Eu estava usando Redis como lida bem com filas. Inicialmente, eu estava gerenciando o matchmaking no próprio servidor e funcionou muito bem, mas encontrei dois problemas com essa abordagem: não consegui encontrar uma maneira de dimensioná-lo e, em segundo lugar, como o servidor solicita que um novo jogo inicie em outro servidor. Poderia enviar uma mensagem para todos eles, mas a carga não seria equilibrada?
Chris Evans
11
@ ChrisEvans Você não deve se preocupar muito com o dimensionamento, um processo simples de correspondência pode lidar com milhares de iniciações de jogos por segundo. Se você codificá-lo bem, não precisará que a correspondência seja dimensionada para vários processos, mesmo se você conseguir milhões de clientes. Quanto ao balanceamento da carga nos servidores de jogos, uma abordagem simples de rodízio, em que cada servidor de jogo recebe um novo jogo, por sua vez, é razoavelmente eficaz se os servidores geralmente são capazes de lidar com um grande número de jogos cada. Caso contrário, você poderá perguntar periodicamente aos servidores do jogo como eles estão ocupados, isso não precisa acontecer uma vez por novo jogo.
Aaaaaaaaaaaa 2/03