想象一下,一个拥有500多个播放器的开放世界,其数据更改速度高达20个更新/播放器/秒。上一次我在类似的MMORPG中工作时,它使用SQL,因此很笨拙,无法始终查询数据库。而是将所有播放器作为C ++对象从数据库加载到内存中并使用它们。也就是说,它是垂直缩放的。可以使该服务器水平扩展吗?是否有一个旨在同时支持该数量的更新的数据库?
想象一下,一个拥有500多个播放器的开放世界,其数据更改速度高达20个更新/播放器/秒。上一次我在类似的MMORPG中工作时,它使用SQL,因此很笨拙,无法始终查询数据库。而是将所有播放器作为C ++对象从数据库加载到内存中并使用它们。也就是说,它是垂直缩放的。可以使该服务器水平扩展吗?是否有一个旨在同时支持该数量的更新的数据库?
Answers:
500名玩家都进行交流的测试案例,即250K信息流以20Hz的速度传播。假设每个消息100字节,则其内部带宽约为500MB /秒。听起来雄心勃勃。特别是在过程之间。
如果将播放器分成100个组,则速度会降低到20MB /秒,依此类推。这就是为什么MMO具有区域,并且在这些区域中几乎没有影响的气泡,等等,直到带宽变得合理为止,等等。
最初的问题可以说是,如果您有10个人全部共享实时信息,但是您希望有500个人全部共享,那将是通信链接的指数增长,而我们如何解决这个问题。恐怕没有我听说过的魔术子弹可以神奇地使几何级数消失。
不要使用数据库进行通信,这就是消息传递的目的。使用数据库执行交易并存储您不希望玩家输掉的信息。我熟悉的大多数MMO仅每1-10分钟或在诸如区域转换或在设计中输入“安全”区域等方便点时使用动态播放器信息更新数据库。
无论距离多远,您可能都必须重新设计每个玩家的游戏需求,才能实时更新每个其他玩家的背包内容。
还要将更新模式从20Hz更改为基于距离的速度,1英里远的人不需要知道您在230.6秒时移动了1英尺,然后在231.4秒时又移动了1英尺,他们就可以应对您每10英尺移动15英尺的情况秒。
使用关注区域过滤。如果一个世界分成3台服务器,并且服务器1上的区域与服务器3的区域相距甚远,则根本没有理由让他们共享有关实体的信息。
同样,在单个服务器上,仅将相关信息发送给客户端。如果玩家A在地图上与玩家B完全相反的一端,则没有理由将有关B的更新发送给A,反之亦然。
如果您在一个连续的世界中有多个服务器,则服务器2上的某个边缘附近的实体将与服务器1上的实体接近。您可以将实体的“权威”服务器中的更新发送到其他服务器(如果适用) ,并根据需要将所有消息转发到权威服务器。
是的,在这种情况下,特定实体的一台服务器将有些过时。不要试图解决这个问题。只是处理它。假设实体可能有点过时。仅在权威拥有实体的服务器上执行任何需要最新信息的逻辑。当一个实体影响另一个实体时,请发送一条消息,并假设它可能需要经过多个游戏逻辑滴答之后才能处理并更新您的视图。
这种设计还使线程化单个服务器变得更加容易。任何实体都不应直接修改另一个实体,而只能发送消息,并且应假定本地每个服务器/每个线程的代理缓存已过时。
例如,如果实体A攻击实体B,则不要检查B的寿命,如果它命中0,则不发送死亡消息。只需发送“损坏”消息,让B的权威服务器处理它,然后处理如果实体A关心服务器B稍后发出的“实体死亡”消息。
这同样适用于任何大型的,可扩展的非游戏应用程序。中央数据库并不是一种神奇的即时共享技术。为了保持高吞吐量,两台服务器必须批量异步地与消息通信。因此,诸如AMPQ等技术的普及。数据库用于存储并出于必要而支持同步,从而使其可以用于通信,而不是因为它们本身是用于同步或通信的。
你将可能感兴趣的这篇文章Gamasutra上,其中在线前夕开发商讨论如何有可能成功地运行游戏有40万个活跃的球员......在一个SQL数据库。
不要将数据库视为某种实时共享的世界模型,该模型始终存储所有内容,就像您已经注意到的那样,这可能行不通。
而是将数据库更像是一个自动更新的保存文件:您仅偶尔更新数据库,例如,当玩家登录或注销或从一个区域移动到另一个区域时,或者在您不想成为重要事件时在服务器崩溃的情况下丢失。
就像您的原始示例一样,实际的实时世界状态应由游戏服务器保存在内存中。现在,水平扩展的诀窍在于,并非每个服务器都需要随时了解所有信息。例如,如果玩家A在服务器A的区域A中玩游戏,则运行区域B的服务器B通常不需要知道玩家A的背包里有什么东西-并且,如果确实由于某些原因需要知道它(例如,因为区域B中的玩家B在A)上施放了某种远程监视咒语,所以它可以向另一台服务器询问该信息。
这确实需要您为服务器分配明确的责任,以便当服务器B想了解玩家A的背包时,它将知道哪个服务器具有有关该服务器的权威信息。您可能还希望包括某种更新订阅机制,以便例如服务器B可以告诉服务器A“ 我有某人在监视玩家A,让我了解他们所做的一切,直到我告诉其他人为止。 ”您可能会还希望包括一些重要的全球性事件的全球广播系统,玩家无论身在何处都可能需要了解这些事件;当然,此类事件也应记录在数据库中,但是让它们主动广播到所有服务器意味着服务器不必继续轮询数据库以获取更新。
其他答复也很好地指出了如何使用数据库,而不是使用数据库进行通信。您可能需要考虑的另一方面是根据需要如何将信息传达给其他实体来对更新进行分类。您可以分发消息传递并使用pubsub机制在实体之间传递更新,而不是与服务器进行通信。例如,您可能会根据与您接近的人来区别对待位置:
您可以通过定期扫描半径2 * R(或基于实体的更新速率和最大速度的半径的倍数)内的实体,并将该实体订阅另一个实体的精确或不精确的位置信息,来传达实体的位置信息。
您可以针对不同类型的信息采用不同的策略,将常见的事物分组到相同的消息队列中,或者对需要发送到不同实体的消息使用不同的队列(或者只是将它们发送到最广泛的实体集,如果它们被丢弃,则将其丢弃) '没有用)。