Formato de log de jogos para servidores MMO

12

Um log de eventos do jogo (em oposição a logs de erro / depuração) para um cluster / shard inteiro é muito útil para um MMO comercial que esteja em um ambiente de produção ao vivo, fornecendo suporte vital para o atendimento ao cliente e os meios para análises históricas.

O projeto em que estou trabalhando atualmente usa um banco de dados relacional para armazenar todos os logs de eventos do jogo e, embora esse método funcione bem, parece-me que a natureza cronológica somente leitura dos logs permitiria um formato de armazenamento mais eficiente .

No entanto, não sei por onde começar a aprender sobre a criação de formatos de log binário personalizados. Quais são as suas experiências com a criação de formatos de log personalizados ou com artigos / artigos recomendados sobre o assunto?

Charles Ellis
fonte

Respostas:

7

Em Stendhal , resolvemos o problema de desempenho adicionando eventos de jogos a uma fila e processando-os de forma assíncrona em segundo plano .

No nosso caso, os eventos não são apenas registros, mas objetos que têm um pouco de lógica, porque em alguns casos precisamos fazer duas inserções com um link entre eles. Por exemplo, na primeira vez em que um item é tratado no jogo, ele precisa ser inserido na tabela de itens antes que um evento de item possa ser registrado.

Mas escrever o log é apenas um lado do problema:

Quais perguntas você deseja responder com os logs?

É fácil apenas ler o log completo em ordem cronológica; ou filtrá-lo para um jogador.

Mas pode haver perguntas como:

  • Quais itens Anton colocou no chão que foram recolhidos por Beth ontem? Qual jogador os possui agora? (Anton reclamou sobre seu item ser roubado)
  • Quanto tempo um jogador médio precisa para atingir o nível 100? Quais jogadores foram significativamente mais rápidos? apenas para os primeiros caracteres?
  • Existem jogadores que lidam com grandes quantidades de dinheiro do jogo? Para quais jogadores é passado? Sem nada valioso em troca?
  • Os jogadores fracos são capazes de matar criaturas fortes que não deveriam ser capazes de matar legalmente?
  • ...

Em Stendhal, usamos um banco de dados relacional para logs de jogos, porque essa é a maneira mais fácil de permitir consultas ad-hoc de alto desempenho. Se você usa um formato de log personalizado, basicamente precisa codificar todas essas consultas quando necessário. E fazer isso com desempenho suficiente fica um pouco difícil.

Nossa tabela gameEvents possui 51.429.139 linhas (no ano passado) e temos uma tabela dedicada de itenslog que possui 60.360.657 linhas (o tempo todo) para 15.893.831 itens.

Hendrik Brummermann
fonte
Qual a velocidade da pesquisa no seu banco de dados? Tenho um banco de dados semelhante com logs e temos cerca de 100.000.000 de linhas após três meses. Usamos o MySQL como armazenamento e seu desempenho é ruim. A consulta simples que lista todas as ações de um jogador (apenas 20.000) linhas geralmente leva mais de 60 segundos.
Balon
1
Consultas simples nas colunas do índice são instantâneas. As consultas complexas podem demorar um pouco, mas ocorrem 60 segundos, mas são muito raras. Nós indexamos a tabela muito fortemente e compensamos a penalidade na inserção, fazendo-as de forma assíncrona.
Hendrik Brummermann 11/01
Hmmm, acho que meu problema é que o conjunto de resultados é bastante grande, geralmente entre 3000 e 150000 registros para um jogador. Portanto, esse pode ser o motivo pelo qual demora tanto tempo, porque funciona muito rápido para pequenos conjuntos de resultados.
Balon
4

O que você quer dizer com eficiência? Seja o tamanho do disco ou a velocidade da consulta, um banco de dados relacional quase certamente superará ou será igual ao seu formato binário proprietário e será muito mais fácil e flexível de usar.

Cada tabela que você usa em um banco de dados relacional permite especificar exatamente o byte exato quanto espaço por linha você permitirá. Se você não está registrando texto sem formatação - e "registro de eventos do jogo (em oposição a registros de erro / depuração)" implica que você não é, ou pelo menos não precisa -, a abordagem de campo de largura fixa de um O banco de dados relacional é bastante próximo do ideal em termos de espaço, o que os torna bastante rápidos em primeiro lugar. Além disso, os bancos de dados relacionais são bastante úteis para criar índices para acesso muito rápido e otimizar consultas para tirar o máximo proveito deles.

Então, eu recomendo ficar com o que você tem.

Kylotan
fonte
Obrigado pela resposta (e obrigado aos outros que enviaram respostas abaixo)! Quanto mais eu penso sobre isso, mais parece que um RDBMS é o ajuste adequado para esse tipo específico de log. Não seria muito difícil projetar um formato de log personalizado que fosse bem indexado para tipos básicos de pesquisas, mas com o tipo de consultas complicadas que são frequentemente usadas por CSRs e análises de jogos, é necessária uma abordagem mais geral - nesse ponto um produto estabelecido terá desempenho superior na maioria dos casos.
Charles Ellis
A configuração personalizada do log de eventos seria útil para a reprodução estritamente cronológica e para as gravações de demonstração do FPS, mas esse é um problema muito diferente de resolver. Alguém tem experiência no desenvolvimento de algo semelhante a gravações demo para jogos cliente-servidor massivamente multiplayer?
Charles Ellis
Dependendo do modelo de processamento lógico do lado do servidor, pode ser possível armazenar apenas todas as entradas, marcadas com a hora de chegada no servidor, que pode ser reproduzida. O problema tende a surgir na reprodução, pois é necessário reproduzir cada entrada individual e modelar qualquer outro fator (por exemplo, sementes aleatórias, entradas implícitas, como coisas que são alteradas com base na latência, etc.). Mas não existe um sistema único para todos - depende de como o servidor funciona.
Kylotan
3

É verdade que você provavelmente poderia salvar alguns bytes com um formato personalizado, ou apenas com o texto compactado em gzip, o armazenamento é barato e, portanto, não vale mais a pena otimizar. O mais importante é lidar com coisas como buffer e consulta de E / S, ambas as quais um servidor SQL pronto para uso provavelmente se sai muito bem. Se estiver funcionando para você nessas frentes, eu correria com ele. Escrevemos nosso próprio servidor de log de buffer, que grava em arquivos personalizados e, em seguida, possui um programa analisador separado para lê-lo em um banco de dados para consultas, eu não o recomendaria.

coderanger
fonte
0

Atualmente, os bancos de dados relacionais são ineficientes, mas ao armazenar o tipo de logs de que você está falando, você realmente não precisa de eficiência, porque eles não serão constantemente acessados ​​pelo jogo ou por seus usuários - apenas sua equipe precisará para ler os dados.

Portanto, "eficiência" não importa tanto. O que importa mais é encomendar os dados de uma maneira que facilite a história do que os usuários estão fazendo no jogo. Seus desenvolvedores geralmente precisam consumir esses dados e exibi-los em uma interface fácil de ler para analistas. Às vezes, os analistas precisam consultar os dados para se aprofundar no comportamento do usuário. Por exemplo, se os jogadores estiverem comprando um determinado item antes de uma atualização, mas pararem de comprá-lo após uma atualização, o analista se beneficiará escrevendo certas consultas que expõem certos números sobre o comportamento em torno dessa compra para determinar por que os usuários não a compram mais. É melhor que eles tenham uma linguagem de consulta padrão para trabalhar e que esteja bem documentada. Se eles tiverem que fazer essas consultas em um formato binário personalizado, seus trabalhos serão muito mais difíceis,

Geralmente os eventos do jogo são parecidos com este (este é o formato do DeltaDNA em particular)

{
 "eventName":"specific event code – eg. gameStarted",
 "userID":"ABCD1-4321a879b185fcb9c6ca27abc5387e914",
 "sessionID":"4879bf37-8566-46ce-9f3b-bd18d6ac614e",
 "eventTimestamp":"yyyy-mm-dd hh:mm:ss.SSS",
 "eventParams":
  {
   "platform":"WEB",
   "param1":"stringParam",
   "param2":true,
   "param3":1234,
   "param4":["a","b","c"]
  },
}

O evento geralmente inclui um nome de evento, um ID do usuário, um ID de sessão, registro de data e hora e parâmetros que permitem gravar os dados que achar úteis para gravar em torno desse evento. E, na minha experiência, os formatos de banco de dados relacional são os melhores para gravar essa estrutura.

Rei Zaphod
fonte