好吧,我花了一个多星期试图弄清楚这一点无济于事,所以如果有人有线索,你就是英雄。这不是一个容易回答的问题,除非我是个笨蛋。
我正在使用node-http-proxy将粘性会话代理到在不同端口上运行的16个node.js工作者。
我使用Socket.IO的Web套接字处理大量不同类型的请求,并使用传统请求。
当我通过node-http-proxy将服务器切换到代理时,一个新的问题随之而来,我的Socket.IO会话有时无法建立连接。
我实际上无法在我的生活中稳定地重现它,唯一的方法是将其从多个客户端投入大量流量到服务器。
如果我重新加载用户的浏览器,它有时可能会重新连接,有时不会重新连接。
我必须代理粘性会话,因为我的应用程序基于每个工作人员进行身份验证,因此它根据其Connect.SID cookie路由请求(我使用的是connect / express)。
这是我的proxy.js文件,它在节点中运行并路由到每个worker:
var http = require('http');
var httpProxy = require('http-proxy');
// What ports the proxy is routing to.
var data = {
proxyPort: 8888,
currentPort: 8850,
portStart: 8850,
portEnd: 8865,
};
// Just gives the next port number.
nextPort = function() {
var next = data.currentPort++;
next = (next > data.portEnd) ? data.portStart : next;
data.currentPort = next;
return data.currentPort;
};
// A hash of Connect.SIDs for sticky sessions.
data.routes = {}
var svr = httpProxy.createServer(function (req, res, proxy) {
var port = false;
// parseCookies is just a little function
// that... parses cookies.
var cookies = parseCookies(req);
// If there is an SID passed from the browser.
if (cookies['connect.sid'] !== undefined) {
var ip = req.connection.remoteAddress;
if (data.routes[cookies['connect.sid']] !== undefined) {
// If there is already a route assigned to this SID,
// make that route's port the assigned port.
port = data.routes[cookies['connect.sid']].port;
} else {
// If there isn't a route for this SID,
// create the route object and log its
// assigned port.
port = data.currentPort;
data.routes[cookies['connect.sid']] = {
port: port,
}
nextPort();
}
} else {
// Otherwise assign a random port, it will/
// pick up a connect SID on the next go.
// This doesn't really happen.
port = nextPort();
}
// Now that we have the chosen port,
// proxy the request.
proxy.proxyRequest(req, res, {
host: '127.0.0.1',
port: port
});
}).listen(data.proxyPort);
// Now we handle WebSocket requests.
// Basically, I feed off of the above route
// logic and try to route my WebSocket to the
// same server regular requests are going to.
svr.on('upgrade', function (req, socket, head) {
var cookies = parseCookies(req);
var port = false;
// Make sure there is a Connect.SID,
if (cookies['connect.sid'] != undefined) {
// Make sure there is a route...
if (data.routes[cookies['connect.sid']] !== undefined) {
// Assign the appropriate port.
port = data.routes[cookies['connect.sid']].port;
} else {
// this has never, ever happened, i've been logging it.
}
} else {
// this has never, ever happened, i've been logging it.
};
if (port === false) {
// this has never happened...
};
// So now route the WebSocket to the same port
// as the regular requests are getting.
svr.proxy.proxyWebSocketRequest(req, socket, head, {
host: 'localhost',
port: port
});
});
Socket连接如此:
var socket = io.connect('http://whatever:8888');
登录后大约10秒钟后,我在这个监听器上收到了这个错误,这没什么用。
socket.on('error', function (data) {
// this is what gets triggered. ->
// Firefox can't establish a connection to the server at ws://whatever:8888/socket.io/1/websocket/Nnx08nYaZkLY2N479KX0.
});
浏览器发送的Socket.IO GET请求永远不会回来 - 它只是在挂起时挂起,即使在错误返回后,它看起来像是超时错误。服务器永远不会响应。
这是工作者收到套接字请求的方式。很简单。所有工人都有相同的代码,所以你认为其中一个人会收到请求并承认它......
app.sio.socketio.sockets.on('connection', function (socket) {
// works... some of the time! all of my workers run this
// exact same process.
});
这是很多数据,我怀疑是否有人愿意面对它,但我完全难倒,不知道接下来要检查哪里,接下来记录,无论如何,要解决它。我已经尝试了所有我知道的问题,看看问题是什么,但无济于事。
好的,我很确定问题出现在node-http-proxy github homepage上的这句话中:
node-http-proxy与< = 0.8.x兼容,如果您正在寻找> = 0.10兼容版请检查caronte
我正在运行Node.js v0.10.13,这个现象正如一些人在github问题上对这个问题进行了评论:它只是随机丢弃了websocket连接。
我试图实现caronte,'更新'的分支,但它根本没有记录,我已经尽力将他们的文档拼凑在一个可行的解决方案中,但我不能让它转发websockets,我的Socket.IO降级为民意调查。
关于如何实施和运作,还有其他想法吗? node-http-proxy昨天有8200次下载!当然有人正在使用今年的Node构建和代理websockets ....
我想完成代理多个node.js工作者的代理服务器(最好是Node),并根据浏览器cookie通过粘性会话路由请求。此代理需要稳定地支持传统请求以及Web套接字。
我不介意通过群集节点工作者完成上述操作,如果可行的话。我唯一真正的要求是根据请求标头中的cookie维护粘性会话。
如果有更好的方法来实现上述目标而不是我正在努力,我就是全力以赴。
答案 0 :(得分:4)
一般来说,我不认为node不是最常用的选项作为代理服务器,I,一次使用nginx作为节点的前端服务器,它是一个非常好的组合。以下是一些instructions来安装和使用nginx粘性会话模块。
这是一个轻量级的前端服务器,配置类似json,可靠且经过严格测试。
如果你想提供静态页面,那么nginx也要快得多。它是理想的配置缓存标头,根据域,粘性会话,压缩css和javascript等将流量重定向到多个服务器。
您还可以考虑像HAProxy这样的纯负载平衡开源解决方案。在任何情况下,我都不相信node是最好的工具,最好只使用它来实现你的后端,并在它前面添加类似nginx的东西来处理通常的前端服务器任务。
答案 1 :(得分:3)
我同意六氰化物。对我而言,通过像redis或某种Message Query系统这样的服务对工作人员进行排队是最有意义的。工作人员将通过Web节点(代理)对Redis Pub / Sub功能进行排队。工作人员会使用“数据”实时回调错误,完成或流式传输数据。事件。也许看看图书馆kue。您也可以滚动自己的类似库。 RabbitMQ是另一个用于类似目的的系统。
如果您已经使用该技术,我会使用socket.io,但您需要使用工具来实现其预期目的。 Redis或MQ系统最有意义,并与websockets(socket.io)配对,以创建实时,富有洞察力的应用程序。
通过Elastic LoadBalancer为aws支持会话关联(粘性会话),这支持webSockets。 PaaS提供商(Modulus)完全这样做。还有satalite为node-http-proxy提供粘性会话,但是我不知道它是否支持webSockets。
答案 2 :(得分:2)
我一直在寻找与此非常相似的东西,目的是动态生成(并销毁)Node.js群集节点。
免责声明:我仍然不建议使用Node; nginx对于您正在寻找的那种设计架构更稳定,甚至更加稳定,HAProxy(非常成熟,并且可以轻松支持粘性会话代理)。正如@tsturzl所指出的,有satellite
,但考虑到下载量较低,我会谨慎行事(至少在生产环境中)。
也就是说,既然你似乎拥有了已经使用Node设置的所有东西,重建和重新架构可能比它的价值更多。因此,要使用NPM安装caronte
分支:
使用http-node-proxy
和/或npm uninstall node-proxy
sudo npm -d uninstall node-proxy
主安装
下载caronte
分支.zip并解压缩。
npm -g install /path/to/node-http-proxy-caronte
sudo npm link http-proxy
我已经使用他们的基本代理示例启动并运行了 - 无论这是否能解决您丢弃的会话问题,只有您知道。