用recluster扩展Nodejs
用recluster扩展Nodejs
简单的多进程服务
使用node.js写的服务器一贯很快,一部分是因为它的非阻塞I/O接口,还有是得益于优化的JavaScript V8引擎。当然,也有限制因素:JavaScript的单线程,所以只会用到处理器的一个内核。不过,通过 recluster (集群)模块(Github: doxout/recluster, MIT) 让多核处理器发挥出它的优势是有可能的。
###使用recluster
Recluster建立在Node.JS内部集群处理能力之上,为扩展子进程提供了一个简单的API,将程序扩展到所有可用的CPU核心。它也增加了一些细微的东西,像指数回避和热重启。
var cluster = recluster("/path/to/worker.js", {
workers: 4,
backoff: 10
});
cluster.run();
<br /> 这样会产生4个工作进程,当一个进程停止会自动恢复。工作进程负责初始化应用,绑定sockets或接口。因为这些,通常使用Node.js的domain来正确封装你的应用,从而捕获异常:
var app = domain.create();
app.on("error", function(err) {
cluster.worker.disconnect();
});
app.run(function() {
http.createServer(function(req, res) {
res.end("Hello World\n");
}).listen(8000);
});
<br /> 使用domain,任何异常都会被domain的错误管理器捕获,然后工作进程就可以优雅地死去了。当需要进程在一个不确定的状态下保持正常工作时,这通常是一个很好的选择。
你可能会注意到,服务是在worker进程中实现的,而非父进程,这意味着我们要在同一个端口上绑定很多次,这明显不行,但是Node的集群机制帮我们处理了这个问题:任何在Worker代码中绑定接口或socket的操作其实都是在它的父进程中实现的;所有的工作进程都会共享同样的socket.
这种对任何Node.js应用的简单处理方法,可以使其很容易地布署一个多进程服务器,但也有限制。
<br /> ###状态和共享内存 Node.js操作的状态共享功能不是很多,而且没有本地的内存共享模型。有些项目需要Node.js提供一个共享的内存绑定,但在底层的灵性性上,可能会大打折扣。
当一个应用从一个进程扩展开来时,维护状态变得越来越没有价值。在理想的状态下,应用应该是完全无状态的。客户端不确定到底是哪一个进程处理了它的请求,所以这并不总是可行的,比如:维护那些像带有用户会话状态的连接,到合适的网络应用这种情况。这样,你会怎么办?
其实Node.js本身就开放了一个消息API,可以用来在进程间传递消息。对于非常简单的应用,这意味着所有的workers都会被通知到状态改变。
// Inside Worker
http.createServer(function(req, res) {
// do something to mutate state, and then...
process.send("State changed!");
}).listen(8000);
// Inside Parent
worker.on("message", function(message) {
// hypothetical connection pool object
pool.broadcast(message);
});
<br /> 这可能在应用非常小的时侯工作地很好,但是在应用中它不能保证状态的统一,而且很容易引起状态的不连续。如果一个worker丢失了一条广播,或者在发送消息前它被kill掉了,这样我们就会有一个不一致的状态,而且非常难以找到原因,甚至变得更难调试了。
这不是说进程内消息没什么用,但当应用扩展变得复杂时它就会略显不足。特别是当我们从一个单进程程序,扩展到多服务器多集群模式时,消息传递就解决不到任何问题了。
更好的选择是创建一个共享的状态代理程序。通常这个后台程序用来替换掉内存状态,我们需要一个足够快的选项:像Redis那样的。(在Node.js中启用Redis不在本文讨论的范围,但它是一个相当简单的工作)。通过这样,我们就可以有效地将“状态”从应用层转移到持久层,还能得到更好地分层这个额外的奖励。
当你的应用把状态保持的需求处理好以后,我们就可以自信地发布我们的应用集群了,然后享用弹性,可扩展的,高性能的构架。
<br />
From:https://medium.com/on-coding/scaling-node-js-with-recluster-f04dd346108c
用recluster扩展Nodejs
简单的多进程服务
使用Node.js编写的服务器一向以速度快著称,这不仅得益于其非阻塞I/O接口,还归功于优化的JavaScript V8引擎。然而,由于JavaScript的单线程特性,Node.js只能利用处理器的一个内核。为了充分利用多核处理器的优势,我们可以使用recluster
(集群)模块。
recluster
基于Node.js内部的集群处理能力,提供了一个简单的API来扩展子进程,从而将程序扩展到所有可用的CPU核心。此外,它还增加了指数回退和热重启等功能。
使用recluster
首先,你需要安装recluster
模块:
npm install recluster
接下来,你可以使用以下代码来启动一个包含多个工作进程的集群:
const recluster = require('recluster');
// 创建一个recluster实例,并指定工作进程的数量以及指数回退的时间间隔
const cluster = recluster('/path/to/worker.js', {
workers: 4,
backoff: 10
});
// 启动集群
cluster.run();
这段代码会启动4个工作进程,当其中一个进程停止时,它会自动重启。每个工作进程负责初始化应用、绑定socket或接口。
异常处理
为了确保工作进程能够优雅地退出,我们通常使用Node.js的domain
模块来捕获异常:
const domain = require('domain');
const http = require('http');
const app = domain.create();
app.on('error', (err) => {
console.error(`Error occurred: ${err.message}`);
cluster.worker.disconnect();
});
app.run(() => {
const server = http.createServer((req, res) => {
res.end('Hello World\n');
});
server.listen(8000);
});
这里,任何未捕获的异常都会被domain
的错误处理器捕获,然后工作进程可以优雅地退出。
状态和共享内存
虽然Node.js本身提供了消息API用于进程间通信,但这并不能很好地解决状态一致性问题。特别是在多进程或多服务器环境下,进程间的消息传递可能会导致状态不一致。
一个更好的解决方案是使用外部存储系统,例如Redis,来管理共享状态。这样,我们可以将状态从应用层转移到持久层,从而提高系统的弹性和可扩展性。
// 在Worker进程中
http.createServer((req, res) => {
// 修改状态并通知其他进程
process.send('State changed!');
}).listen(8000);
// 在Parent进程中
cluster.on('message', (worker, message) => {
// 假设我们有一个连接池对象
pool.broadcast(message);
});
然而,这种方法仍然可能导致状态不一致的问题。更推荐的做法是使用如Redis这样的外部存储系统来管理共享状态,以确保状态的一致性和可靠性。
结论
通过使用recluster
模块,我们可以轻松地将单进程的Node.js应用扩展为多进程应用,从而充分利用多核处理器的优势。同时,使用外部存储系统如Redis来管理共享状态,可以进一步提高应用的弹性和可扩展性。
Recluste 有没有具体的测试数据
还真没有
使用 Recluster 扩展 Node.js
简单的多进程服务
Node.js 以其非阻塞 I/O 接口和优化的 V8 引擎著称,运行速度快。然而,由于 JavaScript 的单线程特性,Node.js 默认只能利用一个 CPU 核心。为了充分利用多核处理器的优势,我们可以使用 recluster
模块来实现多进程扩展。
安装 Recluster
首先,你需要安装 recluster
:
npm install recluster
基本使用
recluster
是基于 Node.js 内置的集群机制,提供了更简便的 API 来管理和扩展子进程。以下是一个简单的示例:
const recluster = require('recluster');
const cluster = recluster('/path/to/worker.js', {
workers: 4,
backoff: 10
});
cluster.run();
这段代码将会启动 4 个工作进程,并且当某个进程挂掉时,会自动重启。工作进程会处理应用的初始化、绑定 socket 或接口等任务。
异常处理
使用 domain
可以确保异常被捕获并优雅地关闭进程:
const domain = require('domain');
const app = domain.create();
app.on('error', (err) => {
cluster.worker.disconnect();
});
app.run(() => {
const httpServer = require('http').createServer((req, res) => {
res.end('Hello World\n');
});
httpServer.listen(8000);
});
在这个例子中,domain
用于捕获任何未处理的异常,确保工作进程能够优雅地退出。
状态与共享内存
在多进程应用中,维护状态可能会变得复杂。Node.js 本身没有内置的内存共享模型,因此需要外部解决方案,例如 Redis。
简单的消息传递
尽管 Node.js 提供了进程间的消息传递功能,但这种方式在应用规模较大时容易导致状态不一致:
// 在 Worker 进程中
process.on('message', (msg) => {
console.log('Message received:', msg);
});
http.createServer((req, res) => {
res.end('Hello World\n');
process.send('State changed!');
}).listen(8000);
// 在 Master 进程中
cluster.on('message', (worker, message) => {
console.log(`Worker ${worker.id} sent: ${message}`);
});
这种方式简单易用,但不适用于复杂的场景。
更好的选择:Redis
使用 Redis 等外部存储系统可以更好地管理状态:
const redis = require('redis');
const client = redis.createClient();
// 在 Worker 进程中
http.createServer((req, res) => {
client.set('key', 'value', (err) => {
if (err) throw err;
res.end('Hello World\n');
});
}).listen(8000);
// 在 Master 进程中
// 不需要额外的逻辑
通过使用 Redis,我们可以将状态管理从应用层转移到持久化层,确保数据的一致性和可靠性。
通过这些步骤,你可以使用 recluster
模块来轻松地扩展 Node.js 应用到多个进程,从而提高性能和稳定性。