Node.js看起来很有趣,但我必须错过一些东西 - Node.js 不是调整为仅在单个进程和线程上运行吗?
那么它如何针对多核 CPU 和多 CPU 服务器进行扩展呢?毕竟,尽可能快的单线程服务器是很棒的,但是对于高负载,我想使用几个 CPU。使应用程序更快也是如此 - 今天的方式似乎是使用多个 CPU 并并行化任务。
Node.js 是如何融入这张图片的?它的想法是以某种方式分发多个实例还是什么?
Node.js看起来很有趣,但我必须错过一些东西 - Node.js 不是调整为仅在单个进程和线程上运行吗?
那么它如何针对多核 CPU 和多 CPU 服务器进行扩展呢?毕竟,尽可能快的单线程服务器是很棒的,但是对于高负载,我想使用几个 CPU。使应用程序更快也是如此 - 今天的方式似乎是使用多个 CPU 并并行化任务。
Node.js 是如何融入这张图片的?它的想法是以某种方式分发多个实例还是什么?
Node.js 绝对可以在多核机器上扩展。
是的,Node.js 是每个进程一个线程。这是一个非常深思熟虑的设计决策,并且消除了处理锁定语义的需要。如果您不同意这一点,您可能还没有意识到调试多线程代码是多么困难。要更深入地解释 Node.js 进程模型以及它为什么以这种方式工作(以及为什么它永远不会支持多线程),请阅读我的另一篇文章。
两种方式:
从 v6.0.X 开始,Node.js 已经包含了开箱即用的集群模块,这使得设置可以在单个端口上侦听的多个节点工作程序变得很容易。请注意,这与通过npm提供的较旧的 learnboost“集群”模块不同。
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
http.Server(function(req, res) { ... }).listen(8000);
}
工作人员将竞争接受新的连接,负载最少的进程最有可能获胜。它工作得很好,并且可以在多核机器上很好地扩展吞吐量。
如果您有足够的负载来处理多个内核,那么您还需要做更多的事情:
在Nginx或Apache之类的网络代理后面运行您的 Node.js 服务- 可以进行连接限制(除非您希望过载条件完全关闭盒子)、重写 URL、提供静态内容和代理其他子服务。
定期回收您的工作进程。对于长时间运行的进程,即使是很小的内存泄漏最终也会累加。
设置日志收集/监控
PS:Aaron 和 Christopher 在另一篇文章的评论中进行了讨论(在撰写本文时,它是最重要的帖子)。对此有几点评论:
共享端口:nginx (port 80) --> Node_workers x N (sharing port 3000 w/ Cluster)
对比
个别端口:nginx (port 80) --> {Node_worker (port 3000), Node_worker (port 3001), Node_worker (port 3002), Node_worker (port 3003) ...}
可以说,单独的端口设置有一些好处(可能减少进程之间的耦合,有更复杂的负载平衡决策等),但设置起来肯定需要更多的工作,并且内置的集群模块很低-适用于大多数人的复杂性替代方案。
一种方法是在服务器上运行多个 node.js 实例,然后在它们前面放置一个负载均衡器(最好是像 nginx 这样的非阻塞式负载均衡器)。
Ryan Dahl在去年夏天在 Google 的技术演讲中回答了这个问题。套用一句话,“只需运行多个节点进程并使用合理的方式让它们进行通信。例如 sendmsg() 风格的 IPC 或传统的 RPC”。
如果您想立即动手,请查看spark2 Forever模块。它使生成多个节点进程变得非常容易。它处理设置端口共享,因此它们每个都可以接受到同一个端口的连接,并且如果您想确保进程在/当它死亡时重新启动,它们也会自动重生。
更新 - 2011 年 10 月 11日:节点社区的共识似乎是集群现在是管理每台机器多个节点实例的首选模块。 永远也值得一看。
您可以使用集群模块。检查这个。
var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', function(worker, code, signal) {
console.log('worker ' + worker.process.pid + ' died');
});
} else {
// Workers can share any TCP connection
// In this case its a HTTP server
http.createServer(function(req, res) {
res.writeHead(200);
res.end("hello world\n");
}).listen(8000);
}
Node Js 支持集群以充分利用您的 CPU。如果您没有使用集群运行它,那么您可能正在浪费您的硬件功能。
Node.js 中的集群允许您创建可以共享相同服务器端口的单独进程。例如,如果我们在 3000 端口上运行一台 HTTP 服务器,它就是一台在单线程上运行在处理器单核上的服务器。
下面显示的代码允许您对应用程序进行集群。此代码为 Node.js 代表的官方代码。
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
Object.keys(cluster.workers).forEach(function(id) {
console.log("I am running with ID : " + cluster.workers[id].process.pid);
});
cluster.on('exit', function(worker, code, signal) {
console.log('worker ' + worker.process.pid + ' died');
});
} else {
//Do further processing.
}
查看这篇文章以获得完整的教程
多节点利用您可能拥有的所有核心。
看看http://github.com/kriszyp/multi-node。
对于更简单的需求,您可以在不同的端口号上启动多个节点副本,并在它们前面放置一个负载均衡器。
未来版本的 node 将允许您分叉一个进程并将消息传递给它,Ryan 表示他希望找到一些方法来共享文件处理程序,因此它不会是一个直接的 Web Worker 实现。
目前还没有一个简单的解决方案,但它还为时过早,node 是我见过的发展最快的开源项目之一,所以期待在不久的将来会有一些很棒的东西。
Spark2 基于现在不再维护的 Spark。Cluster是它的继任者,它有一些很酷的特性,比如每个 CPU 核心生成一个工作进程和重生死掉的工作进程。
您可以通过将cluster模块与os模块结合使用来在多个内核上运行您的 node.js 应用程序,该模块可用于检测您拥有多少 CPU。
例如,假设您有一个server
在后端运行简单 http 服务器的模块,并且您希望在多个 CPU 上运行它:
// Dependencies.
const server = require('./lib/server'); // This is our custom server module.
const cluster = require('cluster');
const os = require('os');
// If we're on the master thread start the forks.
if (cluster.isMaster) {
// Fork the process.
for (let i = 0; i < os.cpus().length; i++) {
cluster.fork();
}
} else {
// If we're not on the master thread start the server.
server.init();
}
The new kid on the block here is LearnBoost's "Up".
It provides "Zero-downtime reloads" and additionally creates multiple workers (by default the number of CPUs, but it is configurable) to provide the best of all Worlds.
It is new, but seems to be pretty stable, and I'm using it happily in one of my current projects.
我正在使用Node worker从我的主进程中以一种简单的方式运行进程。在我们等待正式的方式出现时,似乎工作得很好。
我必须添加在集群模式下使用节点构建与使用 PM2 集群模式等进程管理器之间的重要区别。
PM2 允许在您跑步时零停机时间重新加载。
pm2 start app.js -i 2 --wait-ready
在您的代码中添加以下内容
process.send('ready');
当您
pm2 reload app
在代码更新后调用时,PM2 将重新加载应用程序的第一个实例,等待“就绪”调用,然后继续重新加载下一个实例,确保您始终有一个激活的应用程序来响应请求。
而如果你使用 nodejs 的集群,当你重新启动并等待服务器准备好时会有停机时间。
我为所有可用的 CPU 内核搜索了 Clusterize an app,并在这里找到了我自己。我在哪里找到这个关键字是 Pm2 命令
pm2 示例
这是我发现的
将应用程序集群到所有可用的 CPU 内核:
$ pm2 开始 -i 最大值
如果你需要安装 pm2 使用这些命令
npm install -g pm2
yan add -g pm2
或者
在此处使用此链接
可以使用纯 TCP 负载均衡器 (HAProxy) 将 NodeJS 扩展到多个盒子,这些盒子在每个运行一个 NodeJS 进程的多个盒子前面。
如果您在所有实例之间共享一些常识,则可以使用中央 Redis 存储或类似存储,然后可以从所有流程实例(例如,从所有盒子)访问它
也可以将 Web 服务设计为几个独立的服务器,监听 unix 套接字,这样您就可以将数据处理等功能推送到单独的进程中。
这类似于大多数脚本/数据库 Web 服务器架构,其中 cgi 进程处理业务逻辑,然后通过 unix 套接字将数据推送和拉取到数据库。
不同之处在于数据处理被编写为侦听端口的节点网络服务器。
它更复杂,但最终它必须去多核开发。为每个 Web 请求使用多个组件的多进程架构。