MMO服务器的游戏日志格式


12

整个群集/分片的游戏事件日志(与错误/调试日志相对)对于在实时生产环境中的商业MMO非常有用,它为客户服务提供了至关重要的支持,并提供了历史分析手段。

我当前正在从事的项目使用关系数据库来存储所有游戏事件日志,尽管该方法可以正常工作,但在我看来,日志的按时间顺序排列的只读性质将允许使用更有效的存储格式。

但是,我不确定从哪里开始学习构建自定义二进制日志格式。您在创建自定义日志格式或有关该主题的任何推荐论文/文章方面有什么经验?

Answers:


7

Stendhal中,我们通过将游戏事件添加到队列中,然后在后台异步处理它们来解决性能问题。

在我们的例子中,事件不仅是记录,而且还有一些逻辑的对象,因为在某些情况下,我们需要进行两次插入,并在它们之间建立链接。例如,第一次在游戏中处理物品时,需要先将其插入到物品表中,然后才能记录物品事件。

但是编写日志只是问题的一方面:

您想用日志回答什么问题?

仅按时间顺序读取完整的日志很容易;或为一位玩家过滤。

但是可能会有类似的问题:

  • 昨天贝丝(Beth)捡到了安东(Anton)放在地上的哪些物品?现在哪个玩家拥有它们?(安东抱怨他的物品被盗)
  • 一个普通玩家需要多少时间才能达到100级?哪些玩家的速度显着提高?仅用于第一个字符?
  • 是否有处理大量游戏金钱的玩家?它传递给哪些玩家?没有任何有价值的回报?
  • 弱小的玩家是否能够杀死他们不应该合法杀死的强大生物?
  • ...

在Stendhal中,我们将关系数据库用于游戏日志,因为这是允许执行即席查询的最简单方法。如果使用自定义日志格式,则基本上必须在需要时对所有这些查询进行编码。而要获得足够的性能则变得相当困难。

我们的gameEvents表有51,429,139行(去年),而我们有一个专用的itemlog表,其中有60,360,657行(所有时间)有15,893,831个项目。


搜索数据库的速度有多快?我有与日志类似的数据库,三个月后我们大约有1亿行。我们使用MySQL作为存储,其性能很差。列出玩家所有动作(仅20,000行)的简单查询通常需要60秒钟以上的时间。
Balon 2011年

1
对索引列的简单查询是即时的。复杂的查询可能需要60秒才能完成,但这种情况很少见。我们非常索引该表,并通过异步执行补偿了插入操作的代价。
Hendrik Brummermann

嗯,我认为我的问题是结果集很大,一个玩家的记录通常在3000到150000条之间。因此,这可能是为什么要花这么长时间的原因,因为它对于较小的结果集非常快速。
巴伦2011年

4

您所说的效率是什么?无论是磁盘大小还是查询速度,关系数据库几乎肯定会击败或等于您专有的二进制格式,并且使用起来更加轻松,更加灵活。

关系数据库中使用的每个表几乎都允许您将确切的字节指定为要允许的每行多少空间。如果您不是在记录纯文本-并且“游戏事件日志(与错误/调试日志相对)”表示您不是,或者至少不需要-那么使用固定宽度字段方法关系数据库在空间方面非常接近最优,这使得它们首先非常快。最重要的是,关系数据库非常容易建立索引以进行快速访问,并优化查询以充分利用它们。

因此,我建议您坚持使用现有的东西。


感谢您的回复(并感谢以下提交了答案的其他人)!我考虑的越多,RDBMS看起来就越适合这种特定类型的日志记录。设计一个可以很好地索引基本搜索类型的自定义日志格式并不是很困难,但是对于CSR和游戏分析经常使用的那种复杂查询,则需要一种更通用的方法-在这一点上在大多数情况下,既有产品的表现将优于大市。
查尔斯·埃利斯

自定义事件日志设置对于严格按时间顺序播放ala FPS演示记录非常方便,但这是一个非常不同的问题。有没有人有为大型多人客户端服务器游戏开发类似于演示录制内容的经验?
查尔斯·埃利斯

根据您的服务器端逻辑处理模型,可能仅存储每个输入,并在服务器上标记到达时间,然后可以重播这些输入。由于您需要重播每个输入以及对任何其他因素进行建模(例如,随机种子,隐含的输入,例如根据延迟而变化的内容等),因此问题往往出现在回放中。但是这里没有一个万能的系统-它取决于服务器的工作方式。
Kylotan 2010年

3

的确,您可能可以使用自定义格式保存一些字节,或者只是压缩文本,存储价格便宜,因此确实不值得再进行优化了。更重要的是处理诸如I / O缓冲和查询之类的事情,这两种现成的SQL Server可能都做得很好。如果它在这些方面对您有用,我会同意的。我们编写了自己的缓冲日志服务器,该服务器写入自定义文件,然后有一个单独的解析器程序将其读入数据库以进行查询,我不建议这样做。


0

如今,关系数据库因效率低下而被淘汰,但是在存储您正在谈论的日志类型时,您实际上并不需要效率,因为游戏或其用户不会经常访问它们-仅您的团队需要读取数据。

因此,“效率”并不重要。更重要的是,以一种易于讲述用户在游戏中所做的事情的方式对数据进行排序。开发人员通常需要使用此数据并将其显示在分析人员易于阅读的界面中,分析人员有时需要查询数据以深入了解用户行为。例如,如果玩家在更新之前购买了某个物品,但在更新之后停止购买,那么分析师将可以通过编写某些查询来公开某些有关购买行为的信息,从而确定用户为什么不再购买它,从而从中受益。最好是如果他们有标准的查询语言配合使用,并且有据可查。如果他们必须将这些查询转换为自定义二进制格式,那么他们的工作就会变得更加困难,

通常,游戏事件看起来像这样(特别是DeltaDNA的格式)

{
 "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"]
  },
}

事件通常包括事件名称,用户ID,会话ID,时间戳和参数,这些参数使您可以记录对记录该事件有用的任何数据。以我的经验,关系数据库格式最适合记录这种结构。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.