在node上使用cluster和socket.io-redis扩展node.js socket.io@1.*.*

时间:2014-09-30 14:29:17

标签: node.js heroku redis socket.io scale

有没有人知道一个很好的解决方案来扩展基于node.js - socket.io的应用程序在多个核心上?我目前正在测试socket.io文档中提供的解决方案,在多个节点上使用socket.io,但没有取得具体成功。

我已经在github上创建了一个游乐场:https://github.com/liviuignat/socket.io-clusters这是一个来自socket.io站点的聊天应用程序的位修改副本。它使用expressclustersocket.io@1.1.0socket.io-redis

目前在分支sticky-session中使用feature/sticky的实现似乎也有效。

最后,应用程序需要发布到 Heroku ,扩展到多个dynos。

最初我尝试做类似的事情 - 只为集群节点启动服务器,但我总是收到错误:失败:在收到握手响应之前连接已关闭

if (cluster.isMaster) {    
  for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', function(worker, code, signal) {
    console.log('worker ' + worker.process.pid + ' died');
  });
} else {
  var server = new Server({
      dirName: __dirname,
      enableSocket: true
    })
    .setupApp()
    .setupRoutes()
    .start();
}

然后我尝试为主节点启动服务器:

if (cluster.isMaster) {
  var server = new Server({
      dirName: __dirname,
      enableSocket: true
    })
    .setupApp()
    .setupRoutes()
    .start();

  for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', function(worker, code, signal) {
    console.log('worker ' + worker.process.pid + ' died');
  });
} else {
  var server = new Server({
      dirName: __dirname,
      enableSocket: true
    })
    .setupApp()
    .setupRoutes()
    .start();
}

我也在分支sticky-session中使用socket.io-redisfeature/sticky进行了尝试,这似乎取得了成功,但似乎仍然不是一个好的解决方案:

if (cluster.isMaster) {
  sticky(function() {
    var server = new Server({
        dirName: __dirname,
        enableSocket: true
      })
      .setupApp()
      .setupRoutes();
    return server.http;
  }).listen(3000, function() {
    console.log('server started on 3000 port');
  });

  for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', function(worker, code, signal) {
    console.log('worker ' + worker.process.pid + ' died');
  });
} else {
  sticky(function() {
    var server = new Server({
        dirName: __dirname,
        enableSocket: true
      })
      .setupApp()
      .setupRoutes();
    return server.http;
  }).listen(3000, function() {
    console.log('server started on 3000 port');
  });
}

接下来的几天我会做更多的测试,但如果有人提出一些想法,那将会有很大的帮助。

谢谢,

1 个答案:

答案 0 :(得分:2)

您可能正在寻找socket.io-redis。 http://socket.io/blog/introducing-socket-io-1-0/(滚动到&#39;可扩展性&#39;)

以下是有关如何使用socket.io + express创建脚手架的简短示例:

var cluster = require('cluster');

var express = require('express')
    , app = express()
    , server = require('http').createServer(app);

var
    io = require('socket.io').listen(server)
    var redis = require('socket.io-redis');
    io.adapter(redis({ host: 'localhost', port: 6379 }));



var workers = process.env.WORKERS || require('os').cpus().length;

/**
 * Start cluster.
 */

if (cluster.isMaster) {

  /**
   * Fork process.
   */

  console.log('start cluster with %s workers', workers-1);
  workers--;
  for (var i = 0; i < workers; ++i) {
    var worker = cluster.fork();
    console.log('worker %s started.', worker.process.pid);
  }

  /**
   * Restart process.
   */

  cluster.on('death', function(worker) {
    console.log('worker %s died. restart...', worker.process.pid);
    cluster.fork();
  });


} else {
  server.listen(process.env.PORT || 9010);
}

Redis有pub / sub,所有socket.io节点都需要订阅redis来获取来自频道的所有消息。这样,一个进程可以向通道(发布)广播消息,并且所有其他进程以最小延迟接收消息以将它们广播到它们的连接客户端(订阅)。您甚至可以使用基于redis的会话扩展它。

您所指的群集模块在我看来有点误导。就我理解的概念而言,它有助于创建独立的子流程,但不会同步&#39;跨多个节点的通道。如果您的客户不需要与他人沟通,那就没事了。如果要向所有节点上的所有连接客户端广播消息,则需要redis模块。