Socket.io 和多个Dyno在Heroku Node.js应用程序上。在建立连接之前关闭 WebSocket



我正在构建一个部署到Heroku的应用程序,该应用程序使用Websockets。

当我只使用1个dyno时,websockets连接正常工作,但当我扩展到>1时,我会得到以下错误

岗位http://***。herokuapp.com/socket.io/?EIO=2&transport=轮询&t=1412600135378-1&sid=zQzJJ8oPo5p3yiwIAAAC400(错误请求)套接字.io-1.04.js:2

到的WebSocket连接'ws://***。herokuapp.com/socket.io/?EIO=2&transport=websocket&sid=zQzJJ8oPo5p3yiwIAAAC'失败:在建立连接之前,WebSocket已关闭。socket.io-1.04.js:2

我正在使用Redis适配器来启用多个web进程

var io = socket.listen(server);
var redisAdapter = require('socket.io-redis');
var redis = require('redis');
var pub = redis.createClient(18049, '[URI]', {auth_pass:"[PASS]"});
var sub = redis.createClient(18049, '[URI]', {detect_buffers: true, auth_pass:"[PASS]"} );
io.adapter( redisAdapter({pubClient: pub, subClient: sub}) );

这是在localhost上工作的(我使用foreman来运行它,就像Heroku一样,我正在启动两个web进程,和Heroku上一样)。

在实现redis适配器之前,我遇到了一个websockets握手错误,所以适配器产生了一些影响。而且它现在偶尔也会工作,我想当套接字匹配同一个网络dyno时。

我也尝试过启用粘性会话,但它始终不起作用。

var sticky = require('sticky-session');
sticky(1, server).listen(port, function (err) {
  if (err) {
    console.error(err);
    return process.exit(1);
  }
  console.log('Worker listening on %s', port);
});

我是Heroku的Node.js平台所有者

WebSockets在Heroku上跨多个dynos开箱即用;socket.io(和其他实时libs)使用无状态进程(如xhr轮询)的回退,这些进程在没有会话关联的情况下中断。

要扩大socket.io应用程序的规模,请首先按照socket.io:中的所有说明进行操作

  • http://socket.io/docs/using-multiple-nodes/

然后,在你的应用程序上启用会话相关性(这是一个免费功能):

  • https://devcenter.heroku.com/articles/session-affinity

我花了一段时间试图让socket.io在多服务器架构中工作,首先是在Heroku上,然后是许多人建议的Openshift上。

使其在PAAS上同时工作的唯一方法是在客户端和服务器上禁用xhr轮询并设置transports: ['websocket']

在Openshift上,必须使用*.rhcloud.com服务器将服务器的端口显式设置为8000(对于socket.io客户端初始化上的ws–8443,对于wss),如本文所述:http://tamas.io/deploying-a-node-jssocket-io-app-to-openshift/.

投票策略在Heroku上不起作用,因为它不支持粘性会话(https://github.com/Automattic/engine.io/issues/261),而在Openshift上,由于此问题而失败:https://github.com/Automattic/engine.io/issues/279,这有望很快得到解决。

因此,到目前为止,我找到的唯一解决方案是禁用轮询并仅使用websocket传输。

要做到这一点,请使用socket.io>1.0服务器端:

var app = express();
var server = require('http').createServer(app);
var socketio = require('socket.io')(server, {
  path: '/socket.io-client'
});
socketio.set('transports', ['websocket']);

客户端:

var ioSocket = io('<your-openshift-app>.rhcloud.com:8000' || '<your-heroku-app>.herokuapp.com', {
    path: '/socket.io-client'
    transports: ['websocket']
})

希望这会有所帮助。

可能需要运行RedisStore:

var session = require('express-session');
var RedisStore = require('connect-redis')(session);
app.use(session({
    store: new RedisStore(options),
    secret: 'keyboard cat'
}));

根据前面的q:Heroku+socket.io上的多个dynos广播

我知道这不是一个正常的答案,但我已经尝试让WebSockets在Heroku上工作了一个多星期。在与客户支持进行了多次长时间的交谈后,我终于试用了OpenShift。Heroku WebSockets处于测试阶段,但OpenShift WebSockets是稳定的。我在不到一个小时的时间里就完成了OpenShift上的代码工作。

http://www.openshift.com

我与OpenShift没有任何关系。我只是一个满意的(非付费)客户

我遇到了巨大的问题。有许多问题同时失败,使它成为一场巨大的噩梦。确保你在heroku上缩放socket.io:

  1. 如果您使用集群,请确保实现socketio粘性会话或类似的东西
  2. 客户端的连接url不应该是https://example.com/socket.io/?EIO=3&transport=polling,而是https://example.com/。特别是我使用https,因为heroku支持

  3. 在socket.io 中启用cors

  4. 仅指定websocket连接

对你和其他人来说,这可能是其中的任何一个。

如果你在设置粘性会话集群时遇到问题,这里是我的工作代码

var http = require('http');
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
var sticky = require('socketio-sticky-session');
var redis = require('socket.io-redis');
var io;
if(cluster.isMaster){
  console.log('Inside Master');
  // create the worker processes
  for (var i = 0; i < numCPUs ; i++){
    cluster.fork();
  }
}
else {
  // The worker code to be run is written inside
  // the sticky().
}
sticky(function(){
  // This code runs inside the workers.
  // The sticky-session balances connection between workers based on their ip.
  // So all the requests from the same client would go to the same worker.
  // If multiple browser windows are opened in the same client, all would be
  // redirected to the same worker.
  io = require('socket.io')({transports:'websocket', 'origins' : '*:*'});
  var server = http.createServer(function(req,res){
    res.end('socket.io');
  })

  io.listen(server);
  // The Redis server can also be used to store the socket state
  //io.adapter(redis({host:'localhost', port:6379}));
  console.log('Worker: '+cluster.worker.id);
    // when multiple workers are spawned, the client
    // cannot connect to the cloudlet.
    StartConnect(); //this function connects my mongodb, then calls a function with io.on('connection', ..... socket.on('message'...... in relation to the io variable above
    return server;
}).listen(process.env.PORT || 4567, function(){
  console.log('Socket.io server is up ');
});

更多信息:就个人而言,在不使用websockets的会话中,它会完美地工作(我使用socket.io进行统一游戏。它只在编辑器中完美地工作!)。当通过浏览器连接时,无论是chrome还是firefox,它都会显示这些握手错误,以及错误503和400。

相关内容

  • 没有找到相关文章

最新更新