如何扩展NodeJS有状态应用程序

时间:2017-05-15 15:35:43

标签: node.js docker scalability docker-swarm

我目前正在开发基于网络的MMORPG游戏,并希望根据Docker和DigitalOcean水滴设置自动缩放策略。

但是,我想知道如何才能做到这一点:

我的游戏服务器必须可以跨不同的Docker容器进行拆分每个游戏服务器实例应该就像只有一个巨大的游戏服务器一样。这意味着在一个(角色移动)中发生的每个修改也应该在每个其他游戏服务器中进行镜像。

我试图让它工作(至少在概念上),但无法找到一种方法来正确同步我的所有实例。我应该只使用主设备广播事件还是有替代方案?

我想知道我的MySQL数据库是一样的:因为每个游戏服务器都必须从/向数据库读取/写入,所以当游戏变得越来越大时,我将如何使其正确扩展?我能想到的最佳解决方案是将数据库保存在一台强大的非常强大的服务器上。

据我所知,如果所有游戏服务器都不必共享"这可能很容易。他们的状态,但这主要是因为我可以在活动突然激增的情况下迅速扩展。

(将有不同的"全球和#34;游戏服务器,如A,B,C ...但是这些全球游戏服务器中的每一个都应该在幕后由1-X docker容器组成,运行"真实"游戏服务器,以便"全球游戏服务器只是一个概念)

3 个答案:

答案 0 :(得分:5)

你说的问题太笼统,很难给出具体的回应。但是,让我肆无忌惮,给你一些通用的扩展建议:

  • 从数据库中删除计数器。而是自动递增ID的主键,尝试分配随机UUID。

  • 更改必须通过自包含数据对中心点进行验证的数据。例如,对于身份验证,请使用可由任何主机验证的JSON Web令牌,而不是在DB中使用用户凭据。

  • 使用Consistent Hashing等技术来平衡负载,而无需负载均衡器。当然,使用散列函数可以很好地分配,以避免/最小化冲突。

以上建议基本上是关于将设计从有状态迁移到无状态的方式,尽可能多的方面。如果您无论如何需要提供有状态部分,请尝试猜测哪些实体将有更多机会共享有状态数据并将它们分配到同一个(或接近服务器)。例如,如果您的游戏中有城市,请尝试在同一服务器中分配同一城市中的用户,因为他们更愿意在这些城市之间进行交互(并共享有状态数据),而不是在不同城市中的用户。

当然,如果城市太大而且非常拥挤,你可能需要在更多服务器上对城市进行分区,以避免服务器过载。

答案 1 :(得分:4)

你的问题太宽泛,而且正如其他人所提到的那样是一个普遍的缩放问题。如果您更清楚地说明了您的系统要求,那将会很有帮助。

如果它必须是实时的,那么你可以选择Redis作为你的主数据库,但是你需要奴隶(用于复制),你将不能自动扩展*,因为Redis没有'支持那个。我认为当你处理游戏时可能不是一个好的选择(突然出现尖峰)

*似乎有一些托管解决方案,您需要检查它们

如果它可以接近实时,使用Apache Kafka可以证明是有用的。

还有一个高度可扩展的数据库,其中包含您需要的所有内容CockroachDB我是贡献者,是的!)但您需要运行测试以查看它是否符合您的延迟要求。

总的来说,使用非常强大的服务器是一个糟糕的选择,因为有一个上限,垂直扩展会花费更多。

答案 2 :(得分:2)

横向扩展这样的应用程序有很大的好处。我会写下一些想法。

选项1(有状态):

在规划有状态应用程序时,您需要注意状态的同步(通过PubSub,网络广播或其他方式),并注意每个同步都需要一段时间(不阻止每个操作)。如果这对您没问题,请继续。

假设您在整个群集上每秒有80k次操作。这意味着每个进程都需要每秒同步80k状态更改。这将是你的瓶颈。对于Node.js应用程序来说,每秒处理80k更改是一个很大的挑战(因为它是单线程的,因此阻塞)。

最后,您需要准确配置您希望能够同步的最大更改量,并使用不同的编程语言执行某些测试。需要将同步开销添加到应用程序的一般工作负载中。使用某些多线程语言(如C,Java / Scala或Go。

)可能会有所帮助

选项2(有路由状态):*

在某些情况下,实现不同类型的缩放是可行的。 例如,当您的应用程序可以分解为地图区域时,您可以从一个包含完整地图的应用程序复制开始,当它按比例放大时,它会按比例共享地图。 您需要在应用程序服务器之间实现一些路由,例如,更改世界B =>的城市A中的状态。呼叫服务器xyz。这可以自动完成,但降尺度将是一个挑战。

此解决方案需要更多关注和了解应用程序,并且不像选项1那样容错,但它可以无限扩展。

选项3(无国籍):

将状态移动到其他应用程序并在其他地方解决问题(如Redis,Etcd,...)