mmorpg如何存储数据?


22

我想在我的server.exe中使用sql数据库。

假设有1000位用户在线。玩家在玩游戏时会更改其数据。服务器需要保存这些更新。

但是如何?

我认为有两种方法:

1)服务器将在运行时保存在ram中,并且有时或每小时服务器将从ram将数据(更新)写入sql数据库。但是,如果断电或服务器关闭,更新将无法保存。当然,我不想丢失更新。

2)服务器将在运行时将更新保存在数据库中。但是速度会怎样?我想到了一种方法。我将在下面显示图片。通过这种方法,我能否为1000名在线玩家获得足够的速度? 在此处输入图片说明


11
你做过基准测试吗?是什么让您认为数据库操作将成为您的游戏问题?
凌晨

3
如果您的游戏状态实际上是相关的?您确定要使用SQL数据库吗?
停止Harming莫妮卡

6
另外,请阅读如何使用哈希处理密码。或者至少通知用户其密码将另存为纯文本,以便他们知道不要使用其他安全密码。
TomTsagk

24
附带说明一下,如果您想建立一个商业 MMO并问类似这样的问题,则可能应该从较小的东西开始。MMO很难做到,很难做,更不用说对了,而且从业务角度来看,它们也不是那么好。如果这只是个人事务,并且您想增加玩家数量,请从64位玩家开始,然后逐步提高。这比尝试没有经验的从头开始设计“完美”架构要容易得多。看到这个
基金莫妮卡的诉讼

1
您可以编写与存储无关的常规API。然后编写一个适配器,该适配器将数据缓存在RAM中以进行延迟存储。或者,您可以编写适配器,以便在将数据刷新到SQL DB中之前将数据缓存在临时文件中。这样,您可以打开和关闭缓存以找出最佳缓存。您无需编写过多的额外代码,如果您的架构构建正确。
0xC0DEGURU

Answers:


37

我研究过或知道的大多数MMO(或使用类似体系结构的项目)都使用第一种方法:游戏服务器主要与运行服务器进程的计算机上的RAM配合使用,并且仅定期将相关游戏数据序列化到SQL数据库用于存档(如果已使用)。

您注意到的有关电源故障的问题是有效的,但它比过程中崩溃的问题要小(正常运行时间的可靠性通常是您要向数据中心支付的费用之一)。但是还是。您可以通过调整保存间隔(这样一来,故障最多仅花费几分钟的时间),在多台计算机之间分配保存队列,积极确定需要保存的数据量以及实施可重新启动的保存等方法来缓解这些问题。队列。

一般而言,使用SQL Server本身作为主内存会很慢(而且很麻烦)。我在您的提案中没有看到足够的细节,无法确定它是否仅适用于大约1000名玩家-可能会很好。但是我不相信您可以使其具有可扩展性。

此外,它不能解决问题。除非您执行相同类型的可重新启动保存队列的工作,否则保存过程中的电源故障仍然会丢失或破坏数据(即使这样做,也只会严重降低灾难性数据丢失的可能性,但并不能防止这种情况发生) 。

我建议您采用第一种方法。


10
关于“调整保存间隔”,我上次参与的MMO拥有一个基于活动玩家数量的保存间隔。我们知道它可以处理每秒保存X个播放器的数据而不会出现明显的瓶颈,因此我们轮流地将其保存在每秒X个播放器以下。在繁忙的日子里,通常每两分钟左右为每个玩家节省一次,而在经济低迷时期,每分钟可能节省两次。
Meanbits

4
“可重启的存储队列”听起来像是日记,由许多文件系统和数据库引擎实现?
grawity

6
这些问题是不是唯一的大型多人在线游戏,甚至是视频游戏,在所有。现有的几乎每个ORM都提供某种缓存/批处理机制。无需推出自己的解决方案。
BlueRaja-Danny Pflughoeft

3
如果确实要以一定的时间间隔保存到磁盘上,那么我建议您设计一个可以立即保存内容的系统,以备不时之需。这样,如果发生服务器崩溃或某些故障,那么完成某些工作的人就不会太沮丧。
乔恩

5
@Jon,然后您遇到了人们能够复制对象的问题。理想情况下,您可以将整个游戏状态定期保存为单个事务。一旦开始分段保存,就会出现崩溃可能导致数据不一致的情况。可以按需触发崩溃,甚至可以预测何时可能发生崩溃的玩家,可以利用此优势。
Mark

15

1000个播放器可能有问题,也可能没有。这取决于您需要多久更新一次数据库。但是,有一个简单的解决方案:将数据库放在自己的服务器上。


我看了一眼数据库系统如何运作,人们称其为MMO-Lite的一种游戏-我不会透露。但我可以说它始终拥有1000多名玩家,这是抽象的:

  • 他们使用基于文档的“ No-SQL”数据库获取私人角色信息(库存,设备等)。
  • 他们使用更传统的关系数据库来存储公共角色信息,这些信息很少更新(名称,成就等)和统计信息。

在这种情况下,使用基于文档的数据库是提高性能的一个好主意。尽管这样做对执行联接和聚合操作不利,但对访问数据也有好处……但是他们不会对其中的数据进行访问。

另一方面,当他们需要为每个人执行一个对象与另一个对象的更改之类的操作时,需要运行一个逐个字符并逐个更新它们的后台脚本,这需要花费大量时间。


字符的数据既存在于客户机上,又存在于服务器上,并且系统旨在使它们保持同步,并在两侧进行相同的操作。

现在,当玩家使用系统进行交易时(例如,通过NPC或类似方式将某物品交换为另一物品),这具有以下阶段:

  • 客户端检查操作是否有效
  • 客户端将操作发送到服务器(异步操作)
  • 客户端在RAM中更新其模型
  • 服务器检查操作是否有效
  • 服务器在RAM中更新其模型
  • 服务器更新数据库(异步操作)
  • 服务器告诉客户端更改已发生

注意事项

  • 数据库更新尽管是异步的,但还是立即完成。如果由于任何原因游戏服务器宕机,则损失不多。
  • 由于将数据库放在自己的服务器上,因此性能下降不是什么大问题。

玩家之间的交易以类似的方式处理,有额外的规则可以防止玩家欺骗其他玩家,并且在需要撤销交易时具有额外的可追溯性。我听说有一段时间保存的所有事务的特殊日志(以解决有人抱怨时的问题),我不知道该部分的工作原理。


有时出问题了,这有两种可能的结果:

  • 如果错误立即发生,服务器将告知客户端,客户端将还原该操作(玩家看到该操作被撤消)。
  • UI表示播放器有一个项目,但服务器不同意。如果用户尝试使用它,它将询问服务器并失败,从而使伪造的对象不可用。重新加载清单后,虚假对象就会消失,这将作为同步模型的机会。

无论哪种情况,客户端都知道该错误,并将与播放器所做的所有操作一起记录下来。客户端日志一直在发生。然后,在注销时,如果出现错误,客户端会将日志发送到服务器。


该游戏不使用大多数MMORPG拥有的传统的每日或每周停机维护时间。计划的维护通常用于重置计数器,计时器,运行数据库过程。他们也有机会交换服务器版本以进行更新。


谢谢,但是如果玩家从当前位置移动,例如,玩家的动作如何:x:10,y:10,z:10To x:11,y:11,z:11,应该立即将其保存在数据库中吗?如果玩家不断奔跑,那意味着我们每1秒或更短的时间保存一次他的当前位置,如果有成千上万的玩家,那么每秒就有数百万条查询到数据库。这是怎么运作的?
dwix

2
播放器的位置很少保存在数据库中。您只需要在特殊情况下打开菜单,开始篝火,休息等特殊情况。根据游戏的不同,它甚至都不会保存那么详细。有些游戏会让您总是在最近的城镇等地方产卵,这样也可以节省保存位置的麻烦。但是,这变成了基于观点的观点。
Nico

1
在我谈论的游戏中,@ dwix甚至没有保存玩家的位置。如果您注销并登录,或者服务器关闭,则播放器将被放回到安全的已知位置(编辑:这是一个私人实例,如果愿意,它是“房子”,但每个人都一样)。但是,即使在意外断开连接的情况下,某些游戏也会保留玩家的确切位置。为此,通常的做法是较少地存储该信息。无论如何,您不用什么服务器在数据库上等待。
Theraot

1
@dwix在谈论化身的位置时,您并不真正在乎历史价值,对吗?好吧,如果数据库是瓶颈,那就限制数据。与其存储每个服务器的滴答声,不如频繁地存储。这意味着数据库将没有最新值,但不会严重影响性能。同时,服务器仍将更新值保留在RAM中,这就是它的工作方式。附录:老实说,我建议不要存放仓位,但是有些游戏可以这样做。
Theraot


7

两种方法都可用于MMORPG。将所有内容保留在内存中并定期检查将其指向磁盘似乎是最受欢迎的选择,至少对于较旧的游戏而言。它的优点是易于实施和扩展,但使其可靠完全取决于开发人员。SQL数据库提供了ACID属性,这些属性使可靠性更容易,但总体而言,实现起来更复杂,并且在扩展方面可能会遇到问题。

EVE Online是MMO的示例,其中所有内容都存储在SQL数据库中。我认为它达到了大约60,000个并发用户的峰值,并且多年来必须为数据库服务器提供一些昂贵的硬件,以跟上负载。但是,与大多数MMORPG相比,EVE每位用户存储的数据要多得多,并且交易频率和多样性也要高得多。数据库的ACID属性使整个庞大而复杂的数据库始终保持一致状态。

例如,考虑某人向另一个玩家提供物品的情况。EVE的数据库保证即使在崩溃或电源故障的情况下,该物品也只能存放在一个玩家的库存中。也就是说,从一个玩家的库存中删除该物品并将其添加到另一玩家的数据库交易是原子的。交易要么完全完成,要么根本不发生。您不能以该物品既不在玩家的物品库中又不在两者中的状态而结束。

MMORPG必须将播放器数据保存在内存中并定期检查点,才能自己实现这种原子性。一种方法是在每个播放器的数据上同时设置检查点,以确保新检查点在被视为最新检查点之前已完全提交到磁盘。游戏还必须确保在检查点时玩家数据不会更改。在拥有大量活跃玩家的情况下,挑战就变成了所有这一切,而又不会造成玩家会注意到的足够长的延迟。

不要低估一致性的重要性。在开发游戏时,它会崩溃很多。您不需要追踪为什么物品会消失和/或重复,而不是当问题是无关的错误导致游戏在糟糕的时间崩溃时就可以了。而且,当您的游戏上线时,崩溃的方式将比您预期的要多。您的服务器在测试中运行良好,突然就会在满负荷情况下暴露出许多错误,并且播放器会执行您未曾期望的错误。

请注意,大多数MMORPG都不使用SQL数据库来获取与帐户相关的信息,即使它们不是实际的游戏数据也是如此。比使游戏状态保持一致更重要的是保持计费状态保持一致。游戏数据库损坏的最坏情况是您必须从每日备份中还原数据库。帐户数据库损坏的最坏情况是,由于所有退款,您将破产。

对于您的项目,您可以选择任何一种方式。目前,拥有1000个并发用户可能不会突破SQL Server在商用PC上可以处理的限制,但是这在很大程度上取决于交易的性质。如果您熟悉SQL和关系数据库设计,那么它可以为您工作。您需要尽可能地减少事务,对于诸如玩家当前生命值之类的事情,您可能只想定期将它们保存到数据库中,因为此类统计数据不一定是一致的。(在PvP游戏中,他们可能会……)根本不将怪物HP之类的东西存储在数据库中,在大多数游戏中,只有与玩家相关的数据才是持久的。

另一方面,如果您不是SQL向导,则可能会发现将所有数据保存在内存中要简单得多,以使其可靠地工作。SQL数据库使一致性和可靠性更容易,但不是自动的。设计不良的数据库可能会导致性能下降并导致不一致。除非您这样做,否则交易不会是原子的。如果您不虔诚地使用参数化语句,那么您将容易遭受SQL注入攻击。


0

各种游戏以不同的方式存储事物。通常,游戏公司会创建某种方式来实现此目的,并且大多数游戏都使用相同的方式。当然,不同的工作室经常使用不同的方式。SQL当然是用于游戏的,例如CCP(EVE)拥有(或至少拥有)SQL服务器网络,我不确定他们现在是如何做到的。其他人,只需使用大量文件。

也许从创建一个不可知的“数据代理机制”开始,以处理各种游戏数据交易?由于您无论如何都只是在测试,因此请创建一种机制,使您无需从游戏本身的角度就太在乎存储。意思是,集中精力于如何从宿主应用程序中处理此问题。

我个人认为,如果您可以切换实际的商店而不必重写游戏和经纪人本身,那将是一笔巨大的财富。只需切换到具有相同接口的另一个模块,代理即可与之对话。

就其本身而言,存储数据本身可能不会成为问题。在主机和所有客户端之间有效地将数据传输到该存储/从该存储传输数据可能会比较棘手。我是否应交付整个播放器数据集,或者如果将其细分为多个部分,则选择按什么粒度进行分区等?在哪种情况下哪种资源消耗更多?

XML是一种用于发送数据的格式。这样,您就可以更轻松地动态地对其进行分块。一个字符对多个字符,或者一个项目对一组项目,等等。然后,您可以将XML作为“ XML”存储(在SQL中),和/或让SQL以更具事务性的方式将XML从XML分发到您希望如何实际存储数据。

另一种方法是二进制,在运输方面效率更高,但在其他情况下会产生更多成本。

如果有1,000个客户端,则可以从每个客户端开始轻松地存储10 MB,并且仅使用10 GB的有效RAM +添加一些系统管理RAM来管理该数据,例如再增加一到两个GB。您可以将其保留在主机上的RAM中,并且已经可以使用数据结构了。并根据谁在线来动态加载/保存,取决于活动等各种频率。

您甚至可以将每个客户的信息存储在单独的文件中,依此类推。


0

将*在线*播放器保留在ram中,并在注销时将它们推送到数据库(SQLite?MySQL?)中。如果您担心注销期间的IO停顿,请为每个注销提供自己的线程,而不要在主线程/游戏线程中进行(实际上,我为每个在线玩家保留了一个专用的玩家线程,这使联网代码非常容易比做异步网络io方法)

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.