Using cluster in an Expressjs app

前端 未结 3 1949
天命终不由人
天命终不由人 2021-01-31 21:07

I\'m doing a little OJT on my first node project and, while I can stand up a simple server, the app is going to get hammered so using cluster seems like a good idea. I\'ve cobbl

相关标签:
3条回答
  • 2021-01-31 21:37

    Also take a look at cluster2. It's used by eBay and has an express example

    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 讨论(0)
  • 2021-01-31 21:46

    For anyone searching later, here's what I ended up with:

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

    I'm still very early in the node learning curve, but the server starts and appears to have a working running on each core. Thanks to JohnnyH for getting me on the right track.

    0 讨论(0)
  • 2021-01-31 21:52

    Here is my draft of Cluster.js class. Note that we should catch port conflict when you start master process.

    /*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 讨论(0)
提交回复
热议问题