Existe uma maneira de tornar um mundo dinâmico como um MMORPG escalável horizontalmente?


11

Imagine um mundo aberto com mais de 500 jogadores com dados alterando em até 20 atualizações / player / segundo. Na última vez em que trabalhei em um MMORPG semelhante, ele usava SQL, então, obviamente, não era possível consultar o banco de dados o tempo todo. Em vez disso, carregou todos os players do banco de dados na memória como objetos C ++ e os usou. Ou seja, é dimensionado verticalmente. Seria possível tornar esse servidor escalável horizontalmente? Existe um banco de dados projetado para oferecer suporte a essa quantidade de atualizações simultaneamente?


Por que você deseja atualizar o player no banco de dados 20 vezes / segundo?
Balon 23/03

@ Balon é onde estou confuso. Se eu não atualizá-lo no banco de dados, apenas na memória, terei estados diferentes entre máquinas diferentes. Mas acho que as atualizações de banco de dados têm uma sobrecarga enorme, então não vai funcionar para essa quantidade de atualizações?
MaiaVictor

2
Se você realmente acha que máquinas diferentes (ou até processos) precisam de atualizações de 20Hz em centenas de objetos, ignore completamente o banco de dados e use diretamente um sistema de mensagens. Mas o que você realmente pensa que não é o que realmente deseja. O que você quer é ter um escopo sensato de quem precisa saber o que e, em seguida, ter uma maneira de transportar objetos entre escopos de maneira ordenada. Você deve responder à pergunta de por que precisa de atualizações de 20Hz entre máquinas diferentes para obter ótimas respostas; alguém pode pensar em uma nova maneira de analisar o problema.
Patrick Hughes

@PatrickHughes Não sei do que preciso, só estou explicando como o jogo funciona. Os personagens movem 2 a 3 peças / segundo. A caça de um jogador pode estar cercada por alguns monstros, portanto, pelo menos 10 peças / jogador / segundo. Depois, há itens em decomposição no chão, na mochila do jogador. Existem ataques se movendo na direção do jogador, há ataques se movendo na direção do monstro. Há a saúde decadente, a mana sendo usada, os temporizadores que causam dano venenoso ao jogador. Então, as coisas mudam muito rápido. Este é o design do jogo. Como esse design pode ser dimensionado verticalmente?
MaiaVictor

1
Vi isso no HackerNews há pouco tempo: paralleluniverse.co Eles estão trabalhando em um banco de dados que faz todo o material de segmentação / distribuição espacial para você. Eu acho que, sob o capô, eles estão fazendo todas as coisas nas respostas abaixo.
rebocadores

Respostas:


17

Caso de teste de 500 jogadores se comunicando, são 250K fluxos de informações voando a 20Hz. A largura de banda interna para isso seria, assumindo 100 bytes por mensagem, cerca de 500 MB / s. Parece ambicioso. Especialmente entre processos.

Se você separar os jogadores em grupos de 100, isso diminuirá para 20 MB / s, e assim por diante. É por isso que os MMOs têm zonas e, nessas zonas, pequenas bolhas de influência, e assim por diante, até que a largura de banda se torne razoável.

O problema original pode ser afirmado que, se você tem 10 pessoas compartilhando informações em tempo real, mas deseja 500 compartilhando , esse é um crescimento exponencial dos links de comunicação e como podemos contornar isso . Receio que não haja uma bala mágica que eu já tenha ouvido falar que possa fazer magicamente a progressão geométrica desaparecer.

Não use um banco de dados para se comunicar, é para isso que servem as mensagens. Use o banco de dados para impor transações e armazenar informações que você não quer que os jogadores percam. A maioria dos MMOs que eu conheço atualiza apenas o banco de dados com informações dinâmicas sobre jogadores a cada 1 a 10 minutos, ou em pontos úteis, como transições de zona ou entrada de zonas "seguras" no design.

Pode ser necessário reprojetar a necessidade do jogo para que cada jogador, não importa a que distância, tenha atualizações em tempo real do conteúdo da mochila de todos os outros jogadores.

Altere também o padrão de atualização de 20Hz para uma velocidade baseada na distância; alguém a 1,6 km não precisa saber que você moveu 1 pé a exatamente 230,6 segundos; depois outro pé a 231,4 segundos; eles podem lidar com você se movendo a 15 pés a cada 10 segundos.


Resposta impressionante e informativa, obrigado. Mas devo acrescentar que, enquanto o mundo muda em um ritmo muito rápido, um jogador só pode ver outros jogadores imediatamente ao lado dele. Não vejo isso geométrico - 500 jogadores enviam informações para o servidor; o servidor envia informações periodicamente para esses 500 jogadores. É linear, como eu vejo. Mas o ponto principal está no quarto parágrafo: se eu usar apenas o banco de dados para armazenamento, estou carregando dados na memória. Se estou carregando dados na memória de uma máquina, estou criando uma versão dessincronizada do mundo. É isso que eu não entendo.
MaiaVictor

Para 1 cliente: 1 msg de saída + 1 msg de entrada = 2. Para 2 clientes: 2 msg de saída, 2 msg de entrada = 4. Para 3 clientes: 3 msg de saída, 3 msg de entrada = 9. E assim vai. É assim: envie uma mensagem de status, o servidor envia o resultado para mim e para os outros 2 clientes (1 entrada, 3 saídas) e 3 clientes fazendo isso (1 em 9 saídas). Embora pareça linear para apenas um cliente dos 3, você pode multiplicá-lo por todos os clientes para obter a taxa de transferência total do sistema. Quanto à dessincronização, mesmo processos na mesma caixa física ficam fora de sincronia até que a mensagem de status seja criada e enviada; é apenas uma questão de onde o canal esvazia, RAM local ou rede.
Patrick Hughes

5

Use a área de filtragem de interesse. Se um mundo estiver dividido em três servidores e a área no servidor 1 não estiver nem perto da área do servidor 3, não haverá motivo para que eles compartilhem informações sobre entidades.

Da mesma forma, em um único servidor, envie apenas informações relevantes aos clientes. Se o jogador A estiver no extremo oposto do mapa do jogador B, não há motivo para enviar atualizações sobre B para A ou vice-versa.

Quando você possui vários servidores em um mundo contínuo, terá entidades próximas a uma borda no servidor 2 próximas às entidades no servidor 1. Você pode enviar atualizações do servidor "autoritário" de uma entidade para o outro servidor (quando apropriado) e encaminhar todas as mensagens para o servidor autoritativo, conforme apropriado.

Sim, nesse caso, um servidor estará um pouco desatualizado para entidades específicas. Não tente resolver isso. Apenas lide com isso. Suponha que as entidades possam estar um pouco desatualizadas. Execute qualquer lógica que precise de informações atualizadas apenas no servidor que possui as entidades com autoridade. Quando uma entidade afeta outra, envie uma mensagem e assuma que pode levar vários ticks da lógica do jogo antes de ser processada e sua visualização atualizada.

Esse design também facilita muito o encadeamento de um único servidor. Nenhuma entidade deve modificar diretamente outra, apenas enviar mensagens, e os caches locais de proxy por servidor / por thread devem ser considerados um pouco desatualizados.

Por exemplo, se a entidade A atacar a entidade B, não verifique a vida de B e, em seguida, envie uma mensagem de morte se atingir 0. Basta enviar uma mensagem "danificada", deixe o servidor autoritário de B lidar com isso e, em seguida, com qualquer Mensagem "morrido pela entidade" enviada pelo servidor B posteriormente se a entidade A se importar com isso.

O mesmo se aplica a qualquer aplicativo não relacionado a jogos grande e escalável. Um banco de dados central não é uma tecnologia mágica de compartilhamento instantâneo. Dois servidores devem se comunicar com as mensagens, de forma assíncrona, em lotes, para manter um alto rendimento. Daí a popularidade de tecnologias como AMPQ e similares. Os bancos de dados são para armazenamento e oferecem suporte à sincronização por necessidade, permitindo que sejam usados ​​para comunicações, não porque eles próprios sejam destinados à sincronização ou comunicação.


Obrigado, isso acabou com a maioria das minhas dúvidas restantes. Além disso, você me deu a ideia de separar os servidores pelos jogadores, não pelas áreas - isso pareceria mais suave. Cada servidor cuida de x jogadores. Eu realmente gosto disso! Isso é usado? E também, há apenas mais uma coisa. Como perguntei acima, acabei de aprender sobre um novo banco de dados NoSQL, o Couchbase. Ele deveria ser como o CouchDB, exceto com velocidades de gravação / leitura muito rápidas: até 200 mil atualizações por segundo! Talvez isso realmente funcione como um "modelo mundial compartilhado em tempo real" ou ainda não?
MaiaVictor

Não tenho idéia se essa técnica é usada na natureza, além do habitual "sharding" de servidores. Só fazer isso por jogadores e área geográfica significa que cada servidor pode precisar estar ciente de um número muito grande de entidades em um conjunto diversificado de áreas, aumentando a carga do servidor e aumentando consideravelmente a comunicação entre servidores. Fazer isso por área significa que o servidor pode ficar sobrecarregado em áreas lotadas (embora você possa dividir e ingressar em áreas dinamicamente nesse caso), mas significa que cada servidor tem um conjunto menor de entidades e geometria não-jogadores relevantes para acompanhar .
precisa

@Dokkat: Pode ser possível ter algum tipo de "áreas suaves" em que cada servidor lide principalmente com jogadores em uma parte específica do mundo do jogo, mas faça com que eles entreguem o jogador de forma transparente a outro servidor se eles se afastarem demais região do servidor original. Você só precisa garantir que a entrega seja suave o suficiente para que os jogadores não percebam. Você pode até tentar usar algumas técnicas adaptativas sofisticadas para manter grupos de jogadores interagindo no mesmo servidor, mesmo que eles estejam apenas no limite de uma região.
Ilmari Karonen

3

Você provavelmente estará interessado neste artigo no Gamasutra , onde os desenvolvedores do Eve Online discutem como é possível executar com êxito um jogo com 400.000 jogadores ativos ... em um banco de dados SQL.


2

Não pense no banco de dados como um modelo mundial compartilhado em tempo real que armazena tudo sobre tudo o tempo todo - como você notou, isso não pode funcionar.

Em vez disso, trate o banco de dados mais como um arquivo salvo atualizado automaticamente: você atualiza o banco de dados apenas ocasionalmente, como quando os jogadores se conectam ou saem ou se movem de uma zona para outra, ou sempre que algo importante acontecer que você não deseja que seja. perdido em caso de falha do servidor.

O estado real do mundo em tempo real deve ser mantido pelos servidores do jogo, na memória, exatamente como no seu exemplo original. Agora, o truque para o dimensionamento horizontal é que nem todo servidor precisa saber tudo a todo momento . Por exemplo, se o jogador A está jogando na zona A no servidor A, B servidor rodando zona B, normalmente, não precisa saber o que o jogador A tem em sua mochila - e, se faz necessário saber que por algum motivo (por exemplo, porque o jogador B na zona B lança algum tipo de feitiço de espionagem remota em A), pode simplesmente pedir ao outro servidor essas informações .

Isso exige que você atribua responsabilidades claras aos servidores, para que, quando o servidor B quiser saber sobre a mochila do jogador A, ele saberá qual servidor possui as informações oficiais. Você provavelmente também desejará incluir algum tipo de mecanismo de assinatura de atualização, de modo que, por exemplo, o servidor B possa apenas dizer ao servidor A " Eu tenho alguém espionando o player A, mantenha-me atualizado sobre tudo o que eles fazem até que eu diga o contrário. " Você provavelmente também deseja incluir algum tipo de sistema de transmissão global para eventos globais importantes que os jogadores possam precisar saber, independentemente de onde estejam; é claro, esses eventos também devem ser registrados no banco de dados, mas tê-los transmitidos ativamente para todos os servidores significa que os servidores não precisarão continuar pesquisando o banco de dados em busca de atualizações.


Resposta incrível! Era exatamente isso que eu estava perguntando, obrigado. Portanto, talvez a chave seja dividir o servidor em áreas, mantendo a lógica na memória. Mas devo acrescentar: eu acabei de aprender sobre um novo banco de dados NoSQL, o Couchbase. Ele deveria ser como o CouchDB, exceto com velocidades de gravação / leitura muito rápidas: até 200 mil atualizações por segundo! Talvez isso realmente funcione como um "modelo mundial compartilhado em tempo real" ou ainda não?
MaiaVictor

@Dokkat não, não vai. Couchbase não é mágico.
Philipp

2

Outras respostas fizeram um bom trabalho em apontar como usar um banco de dados e não usar um banco de dados para comunicação. Um outro aspecto que você pode procurar é categorizar suas atualizações com base em como as informações precisam ser comunicadas a outras entidades. Em vez de escopo a comunicação com os servidores, você pode distribuir suas mensagens e usar mecanismos de pubsub para comunicar atualizações entre entidades. Por exemplo, você pode tratar a localização de maneira diferente com base em quem está perto de você:

  • A localização precisa e em tempo real pode ser útil dentro do raio R
  • Atualizações de localização menos precisas e menos frequentes podem ser úteis no raio 2 * R
  • Nenhuma informação de localização pode ser necessária além do raio 2 * R

Você pode comunicar informações de localização de uma entidade, periodicamente procurando entidades dentro do raio 2 * R (ou algum múltiplo disso com base na taxa de atualização e velocidade máxima de uma entidade) e assinando a entidade no feed de localização preciso ou impreciso da outra entidade.

Você pode ter estratégias diferentes para diferentes tipos de informações, agrupar coisas comuns nas mesmas filas de mensagens ou ter filas diferentes para mensagens que precisam ir para entidades diferentes (ou apenas enviá-las ao conjunto mais amplo de entidades e ter as mensagens descartadas se elas não é útil).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.