2013-01-18 6 views
7

Ich mache ein wenig OJT auf meinem ersten Knoten-Projekt, und während ich einen einfachen Server aufstehen kann, wird die App gehämmert werden, so Cluster zu verwenden, scheint eine gute Idee zu sein. Ich habe einige Codeschnipsel zusammengeschustert, die ich bei verschiedenen Suchen (einschließlich SO) gefunden habe, aber der Server startet nicht. Ich bin sicher, meine Unerfahrenheit mit Knoten hat mich etwas Dummes tun lassen, aber ich sehe es nicht.Verwenden von Cluster in einer Expressjs App

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); 
} 

ERGEBNIS:

TypeError: Object #<Cluster> has no method 'repl' 

Wenn ich die use Anrufe zu entfernen, die Arbeiter richtig starten, aber process.env.NODE_WORKER_ID ist undefined. Inspizieren process.env zeigt mir, dass es definitiv nicht definiert ist. Vielleicht war der Ausschnitt, den ich benutzte, von einer alten Version, aber ich bin mir nicht sicher, wie ich den Arbeitsthread anders identifizieren könnte.

Wenn jemand kann entschlüsselt, was auch immer ich gekrochen bin, würde ich es wirklich zu schätzen wissen.

+1

Die 'repl'-,' stats'- und 'reload'-Methoden, die Sie aufrufen, existieren nicht auf' cluster'. Beginnen Sie mit dem kanonischen Beispiel aus der [cluster's Dokumentation] (http://nodejs.org/api/cluster.html) und gehen Sie stattdessen von dort aus. – JohnnyHK

+0

Hmmm. Wurde das Cluster-Modul irgendwann vor 0.8.16 (der von mir verwendeten Version) zum Core hinzugefügt? Vielleicht habe ich die ganze Zeit nur an genau den falschen Stellen gesucht. Vielen Dank. –

+0

Ich denke 'cluster' gibt es seit 0.6, aber es wurde in 0.8 etwas überarbeitet. – JohnnyHK

Antwort

13

Für all später suchen, hier ist, was ich am Ende mit:

var cluster = require('cluster'); 
var express = require('express'); 
var path = require('path'); 

var port = 3000; 
var root = path.dirname(__dirname); 
var cCPUs = require('os').cpus().length; 

if(cluster.isMaster) { 
    // Create a worker for each CPU 
    for(var 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 { 
    var app = express(); 
    var routes = require('./routes')(app); 

    app 
    .use(express.bodyParser()) 
    .listen(port); 
} 

noch sehr früh in der Knotenlernkurve, aber der Server startet ich bin und erscheint auf jedem Kern ein Arbeits laufen zu lassen. Danke an JohnnyH, dass er mich auf den richtigen Weg gebracht hat.

+0

kann ich Forky statt Cluster verwenden, wenn ja, dann können Sie mir bitte ein Beispiel dafür geben, es wäre sehr hilfreich ... – Somesh

+0

Hallo Rob, verwenden Sie irgendwelche Websocket-Tools wie Socket.io oder SocketJS oder PubSub? Haben Sie doppelte Protokolle oder Nachrichten oder seltsames Verhalten beim Verbinden oder Trennen von Benutzern festgestellt? Tnx. – Maziyar

+0

@Maziyar - Nein, ich habe keine Websockets für irgendetwas, was ich tue, gebraucht. Es tut uns leid. –

5

Werfen Sie auch einen Blick auf cluster2. Es ist von eBay verwendet und hat ein Express-Beispiel

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); 
}); 
+0

Wont Arbeit für mich. Unter Windows 7 gibt der Aufruf 'require' ein json-Objekt zurück, und wenn ich 'new cluster' versuche, erhalte ich 'object #Object' keine Funktion '. –

4

Hier ist mein Entwurf der Cluster.js-Klasse. Beachten Sie, dass wir beim Starten des Masterprozesses einen Portkonflikt abfangen sollten.

/*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 
    }; 
}; 
+0

Ich denke, das ist eine bessere Antwort. 1) Es modularisiert den benötigten Anwendungsfall in ein NPM-Modul. 2) Die integrierte Verwendung der Domain-Klasse. Eine Ergänzung, die ich machen würde, ist, einen neuen Arbeiter auf dem Domain-Fehler-Ereignis zu starten. – Devnetics

Verwandte Themen