可扩展的 Node.js 应用程序架构
Posted
技术标签:
【中文标题】可扩展的 Node.js 应用程序架构【英文标题】:Scalable Node.js application architecture 【发布时间】:2014-11-15 02:03:27 【问题描述】:过去,我只在本地机器上玩 Node.js,所以我只有单进程 Node.js 应用程序的经验。现在我想创建一个可以在网络上发布的网络应用程序。
这个网络应用就像一个多人游戏——使用Socket.IO 进行客户端-服务器通信,Express 用于处理 HTTP 请求,grunt 用于任务管理等等——我想使用其他 NPM包也适用于各种任务。
我想将此应用程序的架构设计为
启用水平可扩展性(以后,当我有很多访问者时,我不必重写整个应用程序) 尽量减少对不同执行环境的依赖(以最大限度地提高可移植性)如何使用 Node 实现这一点?
我猜高级架构将包括:
不同的服务器进程(每个进程将运行一个 Express 实例并处理传入的 HTTP 请求)。 某处应该有一个负载平衡器。 可选:后台进程可以定期运行并处理“共享数据”由于我的应用程序将是一个多人应用程序,其中每个用户都可以与其他在线用户进行交互,因此我应该将一些通用状态(“共享数据”)存储在可以在这些进程之间共享的某个位置。
为了简单起见,起初我不必持久化这些共享数据,所以我认为我应该使用像 Redis 这样的内存数据存储。
总体情况如下:
这种设计提出了一些问题:
如何产生进程?
我应该使用 Node 的 child_process
或 cluster
模块并手动启动工作进程吗?顺便说一句,是否可以手动启动这些,例如,如果我将我的应用程序部署到Heroku 或Nodejitsu?
或: is there a better way to store these information in a config file?
我的意思是,如果我可以配置我想要的服务器实例数量而不是编辑代码而是一个配置条目会更好。
系统边界?
如果我手动生成进程,那么(我猜)所有进程都将在同一个(虚拟)服务器上运行。
如果这台服务器有 4 个 CPU 核心,那么您最多可以生成 4 个节点实例,因为如果生成更多,您的 CPU 将进行上下文切换,从而破坏整体性能。
如果我需要更多流程实例,我该怎么办?假设我需要 100 个服务器实例。我是否必须将我的应用部署到 25 台服务器并在每台服务器上生成 4 个进程?
在我看来,像 Nodejitsu 这样的托管服务以某种方式隐藏了这个系统边界层,但我不知道它在实践中是如何工作的。
特别是有这个“共享数据”提供者组件。我猜这个提供程序(如 Redis 服务器)必须在不同的服务器上运行,以便所有进程都可以使用它。但在这种情况下,它很容易成为瓶颈,不是吗?
负载均衡器?
如果我使用一些托管服务,我是否必须自己设置负载均衡器层?
编辑:
回答几个实际问题:第一步,我想无缝处理 4-500 个并发用户(Socket.IO 连接)。这是我可以实际实现的访问者数量。
但我只是好奇是否有可能(如果有,如何设计?)设计一个易于扩展的应用程序架构。假设我的网站每天都会流行起来,而不是处理几百个并发用户,第二天我必须为几千个用户提供服务。
据我所知,像 Heroku 和 Nodejitsu 这样的云托管服务可以很容易地适应这些场景——你只需要增加工人 / dynos / 任何东西的数量——但它只有在你有合适的情况下才有效应用架构。
关于共享数据:我不想持久化。我只是想把它保存在内存中。由于 Socket.IO,一方面需要一些共享数据提供者——一个用户将能够向另一个“节点”中的用户发送消息。为此,我将使用 Redis 作为共享数据提供者。 Redis 需要处理的事务数等于使用 Socket.IO 发送/接收的消息量,~1000-1500 条消息/秒。
另一方面,需要一些共享数据提供者,因为我想根据几个标准连接用户。稍后,后台进程将定期重新计算/优化这些连接的概率(“权重”)。我已经知道如何实现高效的数据结构来处理对这个内存表的快速插入/删除。因此,“共享数据提供者”组件将包含一些可以存储这些连接的服务器端代码(可能是 Node.js)。
我知道它是 TL;DR,但我希望它能回答您关于该问题的所有技术问题。 :)
【问题讨论】:
你需要类似 redis 的东西才能在许多机器上使用 socket.io,即使这样,一个机器上的用户向另一个机器上的用户发送消息也会很复杂。跨度> 这大约是 10 个不同的问题,这通常不是 *** 最有效的方式。 @dandavis:是的,我知道。至少 Socket.IO 对此有一个documentation page。 @jfriend00 *** 也可以被视为一个社区 wiki。由于这些问题与单个主题(可扩展性)有关,我认为在 *** 上提出问题是合适的。 @Zsolt - 就像我说的“不是 *** 最有效的方式”。对于某人来说,要回答整个问题,因此在第一个小时内回答为零是一项艰巨的任务。将其分解为较小的问题,OP 可能会立即得到答复。这只是人们自愿提供时间/答案的本性。这个问题确实显示了深思熟虑和先前的研究,但在大多数情况下是一系列架构问题,没有简单的答案。 【参考方案1】:好的,这有很多事情要做。首先,您的关注点分离是适当的,您需要一种进程通信方式,这可以通过 Redis 实例或其他 pub/sub 或 req/res 系统(无论是 redis、kue、zmq 等)。注意:如果您显着增长,您可能仍需要对数据/消息的使用进行分片,至少尽可能多地分片。如果您使用更复杂的消息队列系统(Rabbit 或其他 AMQP),则可以缓解这种情况。
看来您主要关心的是流程管理。一般来说,如果您使用 Heroku,您应该能够扩展每个节点的单个进程,但是您仍然需要外部的协调器节点。如果您是自托管(不是通过 heroku 或类似方式),那么您应该查看 pm2 或 forever ...然后您可以启动多个实例...
在大多数情况下,您的物流/基础设施问题会因您的需求而异。更不用说涉及 CI/CD、docker 等的新策略了。或者你的数据库使用。
【讨论】:
以上是关于可扩展的 Node.js 应用程序架构的主要内容,如果未能解决你的问题,请参考以下文章
React Flux 调度程序与 Node.js EventEmitter - 可扩展?
使用 node.js 更正了大型 RESTful API 的可扩展结构