我正在对我的第一个节点项目进行一些 OJT,虽然我可以建立一个简单的服务器,但该应用程序将会受到重创,因此使用集群似乎是一个好主意。我拼凑了一些在各种搜索(包括 SO)中找到的代码片段,但服务器无法启动。我确信我对 Node 的缺乏经验让我做了一些愚蠢的事情,但我没有看到它。
var express = require( 'express' );
var cluster = require( 'cluster' );
var path = require( 'path' );
var cCPUs = require( 'os' ).cpus().length;
var port = 3000;
var root = path.dirname( __dirname );
if( cluster.isMaster ) {
for( var i = 0; i < cCPUs; i++ ) {
cluster.fork();
}
cluster.on( 'death', function( worker ) {
console.log( 'Worker ' + worker.pid + ' died.' );
});
}
else {
// eyes.inspect( process.env );
console.log( 'Worker: %s', process.env.NODE_WORKER_ID );
var app = express();
var routes = require( './routes' )( app );
app
.use( cluster.repl( root + 'cluster.repl' ) )
.use( cluster.stats({ connections: true, requests: true }) )
.use( cluster.reload( root ) )
.listen( port );
}
结果:
TypeError: Object #<Cluster> has no method 'repl'
如果我删除
use
调用,工作人员会正确启动,但 process.env.NODE_WORKER_ID
是 undefined
。检查 process.env
表明它绝对没有定义。也许我使用的代码片段来自旧版本,但我不确定如何以其他方式识别工作线程。
我该如何解读这个?
对于后来搜索的人,这就是我最终得到的结果:
const cluster = require('cluster');
const express = require('express');
const path = require('path');
const port = 3000;
const root = path.dirname(__dirname);
const cCPUs = require('os').cpus().length;
if (cluster.isMaster) {
// Create a worker for each CPU
for (let i = 0; i < cCPUs; i++) {
cluster.fork();
}
cluster.on('online', function (worker) {
console.log('Worker ' + worker.process.pid + ' is online.');
});
cluster.on('exit', function (worker, code, signal) {
console.log('worker ' + worker.process.pid + ' died.');
});
} else {
const app = express();
const routes = require('./routes')(app);
app.use(express.bodyParser()).listen(port);
}
我仍处于节点学习曲线的早期阶段,但服务器启动并且每个核心似乎都在运行。感谢 JohnnyH 让我走上正轨。
另请查看 cluster2。它被 eBay 使用并有一个明确的示例
var Cluster = require('cluster2'),
express = require('express');
var app = express.createServer();
app.get('/', function(req, res) {
res.send('hello');
});
var c = new Cluster({
port: 3000,
});
c.listen(function(cb) {
cb(app);
});
这是我的 Cluster.js 类草稿。请注意,当您启动主进程时,我们应该捕获端口冲突。
/*jslint indent: 2, node: true, nomen: true, vars: true */
'use strict';
module.exports = function Cluster(options, resources, logger) {
var start = function () {
var cluster = require('cluster');
if (cluster.isMaster) {
require('portscanner').checkPortStatus(options.express.port, '127.0.0.1', function (error, status) {
if (status === 'open') {
logger.log.error('Master server failed to start on port %d due to port conflict', options.express.port);
process.exit(1);
}
});
// Each core to run a single process.
// Running more than one process in a core does not add to the performance.
require('os').cpus().forEach(function () {
cluster.fork();
});
cluster.on('exit', function (worker, code, signal) {
logger.log.warn('Worker server died (ID: %d, PID: %d)', worker.id, worker.process.pid);
cluster.fork();
});
} else if (cluster.isWorker) {
var _ = require('underscore');
var express = require('express');
var resource = require('express-resource');
// Init App
var app = express();
// App Property
app.set('port', process.env.PORT || options.express.port);
app.set('views', options.viewPath);
app.set('view engine', 'jade');
app.set('case sensitive routing', true);
app.set('strict routing', false);
// App Middleware
app.use(express.favicon(options.faviconPath));
app.use(express.logger({ stream: logger.stream() }));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.responseTime());
app.use(app.router);
app.use(require('stylus').middleware(options.publicPath));
app.use(express['static'](options.publicPath));
if (options.express.displayError) {
app.use(express.errorHandler());
}
// App Format
app.locals.pretty = options.express.prettyHTML;
// App Route Handler
if (!_.isUndefined(resources) && _.isArray(resources)) {
_.each(resources, function (item) {
if (!_.isUndefined(item.name) && !_.isUndefined(item.path)) {
app.resource(item.name, require(item.path));
}
});
}
// Start Server
var domain = require('domain').create();
domain.run(function () {
require('http').createServer(app).listen(app.get('port'), function () {
logger.log.info('Worker server started on port %d (ID: %d, PID: %d)', app.get('port'), cluster.worker.id, cluster.worker.process.pid);
});
});
domain.on('error', function (error) {
logger.log.error(error.stack);
});
}
};
return {
start: start
};
};