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

Posted

技术标签:

【中文标题】在 Heroku 上使用集群和 socket.io-redis 扩展 node.js socket.io@1.*.*【英文标题】:Scale node.js socket.io@1.*.* with cluster and socket.io-redis on Heroku 【发布时间】:2014-11-25 05:31:58 【问题描述】:

有没有人知道在多个内核上扩展基于 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

目前在分支feature/sticky 中也有一个使用sticky-session 的实现,似乎效果更好。

最后,应用程序需要发布到 Heroku,在多个 dyno 上进行扩展。

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

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

我还尝试在分支feature/sticky 中同时使用sticky-sessionsocket.io-redis,这似乎成功执行,但似乎仍然不是一个好的解决方案:

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】:

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

这是一个关于如何使用 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 的会话来扩展它。

在我看来,您所指的集群模块有点误导。据我了解这个概念,它有助于创建单独的子流程,但不会跨多个节点“同步”通道。如果您的客户不需要与他人交流,那很好。如果你想向所有节点上所有连接的客户端广播消息,你需要 redis 模块。

【讨论】:

嗨,Steffen,我正在使用 socket.io-redis,但没有成功。 我添加了一个示例,该示例取自我不久前从事的一个项目。当时情况有点不同,但我已经更新它以使用 socket.io-redis for socket.io >=1.0 谢谢,看来我已经设法使它与一个简单的服务器一起工作(参见:github.com/liviuignat/chat-example-cluster/blob/master/index.js)。我会多玩一点,因为在我的主要项目中它仍然存在问题。 嗨,我从上面的链接 (github.com/liviuignat/chat-example-cluster) 更新了 github 示例,以便能够在 Heroku 上托管它,但似乎在 Heroku 上它失败了。有时它也会在我的本地计算机上失败。 Heroku 的网址是:chat-example-cluster.herokuapp.com。所以,我还在苦苦挣扎

以上是关于在 Heroku 上使用集群和 socket.io-redis 扩展 node.js socket.io@1.*.*的主要内容,如果未能解决你的问题,请参考以下文章

Socket IO 在本地机器上工作正常,但在 Heroku 上不工作

为啥我的 socket.io 视频聊天无法在 heroku 上运行?

Socket io 和 Node 在本地工作,但不能在 heroku 上工作

将简单的 Node.js 和 Socket.io 聊天应用程序与 Rails 应用程序连接起来(在 Heroku 上)

Heroku 和 Socket.io,400 个错误请求和许多断开连接

如何在 Socket.io 中与 Heroku 服务器建立 Socket 连接?