我正在构建一个部署到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:
- 如果您使用集群,请确保实现socketio粘性会话或类似的东西
-
客户端的连接url不应该是
https://example.com/socket.io/?EIO=3&transport=polling
,而是https://example.com/
。特别是我使用https,因为heroku支持 -
在socket.io 中启用cors
- 仅指定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。