2013-01-18 13 views
7

Robię małe OJT na moim pierwszym projekcie węzła i, podczas gdy mogę stanąć na prostym serwerze, aplikacja zostanie pobity, więc używanie klastra wydaje się dobrym pomysłem. Wybrałem kilka fragmentów kodu, które znalazłem w różnych wyszukiwaniach (w tym SO), ale serwer się nie uruchomi. Jestem pewien, że moje niedoświadczenie z węzłem powoduje, że robię coś głupiego, ale nie widzę tego.Używanie klastra w aplikacji Expressjs

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

WYNIK:

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

Jeśli usunąć połączenia use robotnicy zaczynają się poprawnie, ale process.env.NODE_WORKER_ID jest undefined. Sprawdzanie process.env pokazuje mi, że zdecydowanie nie jest zdefiniowany. Może fragment, którego użyłem, był ze starej wersji, ale nie jestem pewien, jak zidentyfikować wątek roboczy w jakikolwiek inny sposób.

Jeśli ktokolwiek może rozpakować wszystko, co gram, to byłbym bardzo wdzięczny.

+1

Metody 'repl',' stats' i 'reload', których używasz, nie istnieją na' cluster'. Zacznij od przykładu kanonicznego z ['cluster' docs] (http://nodejs.org/api/cluster.html) i przejdź z tego miejsca. – JohnnyHK

+0

Hmmm. Czy moduł klastra został dodany do rdzenia kiedyś przed wersją 0.8.16 (wersja, której używam)? Może przez cały czas szukałem w niewłaściwych miejscach. Dzięki. –

+0

Myślę, że 'klaster' istnieje od 0.6, ale został przerobiony nieco w 0.8. – JohnnyHK

Odpowiedz

13

Dla każdego szukasz później, oto co skończyło się z:

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

Jestem jeszcze bardzo wcześnie w krzywej uczenia się węzeł, ale uruchomieniu serwera i wydaje się mieć sprawnego działa na każdym rdzeniu. Dzięki JohnnyH za doprowadzenie mnie na właściwą drogę.

+0

czy mogę używać forky zamiast klastra, jeśli tak, to możesz podać mi przykład, byłoby bardzo pomocne ... – Somesh

+0

Cześć Rob, Czy używasz narzędzi Websocket takich jak Socket.io lub SocketJS lub PubSub? Czy widziałeś zduplikowane dzienniki lub wiadomości lub dziwne zachowanie podczas łączenia lub rozłączania użytkowników? Tnx. – Maziyar

+0

@Maziyar - Nie, nie potrzebowałem stron internetowych do niczego, co robię. Przepraszam. –

5

Zobacz także cluster2. Jest używany przez serwis eBay i ma wyraźny przykład:

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

Nie będę pracował dla mnie. uruchomione w systemie Windows 7 wywołanie "require" zwraca obiekt Json, a gdy próbuję "nowego klastra", otrzymuję "obiekt #Object nie jest funkcją". –

4

Oto moja wersja klasy Cluster.js. Zwróć uwagę, że powinniśmy przechwycić konflikt portów, gdy rozpoczniesz proces główny.

/*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

Myślę, że to jest lepsza odpowiedź. 1) Moduluje potrzebny przypadek użycia do modułu NPM. 2) Zintegrowane wykorzystanie klasy Domain. Jednym dodatkiem, który chciałbym zrobić, jest odpalenie nowego pracownika w zdarzeniu błędu domeny. – Devnetics