javascript - nodejs - Node.js http-proxy descarta solicitudes websocket
node proxy request (3)
Bueno, he pasado más de una semana tratando de resolver esto sin éxito, así que si alguien tiene una pista, eres un héroe. Esta no será una pregunta fácil de responder, a menos que sea un tonto.
Estoy usando node-http-proxy para proxy sesiones pegajosas a 16 trabajadores de node.js que se ejecutan en diferentes puertos.
Utilizo los Web Sockets de Socket.IO para manejar un montón de diferentes tipos de solicitudes, y también uso las solicitudes tradicionales.
Cuando cambié mi servidor a un proxy a través de nodo-http-proxy, un nuevo problema surgió de que a veces, mi sesión Socket.IO no puede establecer una conexión.
Literalmente no puedo reproducirlo de forma estable para toda mi vida, con la única forma de convertirlo en enviar mucho tráfico de varios clientes al servidor.
Si recargo el navegador del usuario, a veces se puede volver a conectar, y otras veces no.
Sesiones pegajosas
Tengo que hacer proxy de las sesiones adhesivas ya que mi aplicación se autentica por trabajador, y así enruta una solicitud basada en su cookie Connect.SID (estoy usando Connect / Express)
Vale un código
Este es mi archivo proxy.js que se ejecuta en el nodo y las rutas a cada uno de los trabajadores:
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
});
});
Lado del cliente / Los fenómenos
El zócalo conecta así:
var socket = io.connect(''http://whatever:8888'');
Después de aproximadamente 10 segundos al iniciar sesión, recibo este error en este oyente, lo cual no ayuda mucho.
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.
});
La solicitud Socket.IO GET que envía el navegador nunca regresa; simplemente se queda pendiente, incluso después de que el error vuelve, por lo que parece un error de tiempo de espera. El servidor nunca responde.
Lado del servidor - un trabajador
Así es como un trabajador recibe una solicitud de socket. Bastante simple. Todos los trabajadores tienen el mismo código, por lo que cree que uno de ellos recibiría la solicitud y la reconocería ...
app.sio.socketio.sockets.on(''connection'', function (socket) {
// works... some of the time! all of my workers run this
// exact same process.
});
Resumen
Eso es una gran cantidad de datos, y dudo que alguien esté dispuesto a confrontarlo, pero estoy totalmente perplejo, no sé dónde revisar a continuación, registrar a continuación, lo que sea, para resolverlo. He intentado todo lo que sé para ver cuál es el problema, en vano.
ACTUALIZAR
De acuerdo, estoy bastante seguro de que el problema está en esta declaración en la página de inicio de nodo-http-proxy github :
proxy-nodo-nodo es <= 0.8.x compatible, si está buscando una versión compatible> = 0.10, por favor verifique caronte
Estoy ejecutando Node.js v0.10.13, y los fenómenos son exactamente como algunos han comentado en los temas de github sobre este tema: solo cae las conexiones websocket al azar.
He intentado implementar caronte, la bifurcación ''más nueva'', pero no está documentada en absoluto y he intentado todo lo posible para juntar sus documentos en una solución viable, pero no puedo obtener el reenvío de websockets, mi Socket. IO baja las calificaciones a las encuestas.
¿Hay otras ideas sobre cómo conseguir que esto se implemente y funcione? node-http-proxy tiene 8200 descargas ayer! Seguro que alguien está usando una compilación de Nodo de este año y está procesando websockets ...
Lo que estoy buscando exactamente
Quiero realizar un servidor proxy (preferiblemente Nodo) que se dirija a varios trabajadores de node.js, y que enrute las solicitudes a través de sesiones adhesivas basadas en una cookie del navegador. Este proxy debería admitir de forma estable las solicitudes tradicionales, así como los sockets web.
O...
No me importa lograr lo anterior a través de los trabajadores de nodo agrupado, si eso funciona. Mi único requisito real es mantener sesiones rápidas basadas en una cookie en el encabezado de la solicitud.
Si hay una manera mejor de lograr lo anterior que lo que estoy intentando, estoy totalmente a favor.
En general, no creo que el nodo no sea la opción más utilizada como servidor proxy, yo, por un lado, uso nginx como servidor de interfaz para el nodo y es una combinación realmente excelente. Aquí hay algunas instructions para instalar y usar el módulo de sesiones adhesivas nginx.
Es un servidor frontend liviano con configuración tipo json, sólido y muy bien probado.
nginx también es mucho más rápido si desea servir páginas estáticas, css. Es ideal para configurar los encabezados de almacenamiento en caché, redirigir el tráfico a múltiples servidores según el dominio, las sesiones rápidas, comprimir CSS y JavaScript, etc.
También podría considerar una solución de código abierto de equilibrio de carga pura como HAProxy . En cualquier caso, no creo que node sea la mejor herramienta para esto, es mejor usarlo solo para implementar su backend y poner algo como nginx delante de él para manejar las tareas habituales del servidor frontend.
Estoy de acuerdo con la hexacianida. Para mí tendría más sentido poner en cola a los trabajadores a través de un servicio como redis o algún tipo de sistema de consulta de mensajes. Los trabajadores se pondrían en cola a través de la funcionalidad Pub / Sub de Redis por los nodos web (que son proxy). Los trabajadores devolverían la llamada en caso de error, finalizarían o transmitirían los datos en tiempo real con un evento de "datos". Tal vez echa un vistazo a la biblioteca kue . También puedes rodar tu propia biblioteca similar. RabbitMQ es otro sistema para propósitos similares.
Me pongo a usar socket.io si ya estás usando esa tecnología, pero necesitas usar las herramientas para el propósito previsto. Redis o un sistema MQ tendrían más sentido, y se combinarían muy bien con websockets (socket.io) para crear aplicaciones en tiempo real y perspicaces.
La afinidad de sesión (sesiones adhesivas) se admite a través de Elastic LoadBalancer para aws, esto es compatible con webSockets. Un proveedor de PaaS ( Modulus ) hace esto exactamente. También hay satalite que proporciona sesiones adhesivas para el nodo-http-proxy, sin embargo, no tengo idea si es compatible con webSockets.
He estado investigando algo muy similar a esto, con la intención de generar (y destruir) los nodos de clúster Node.js sobre la marcha.
Descargo de responsabilidad: todavía no recomendaría hacer esto con Node; nginx es más estable para el tipo de arquitectura de diseño que está buscando, o incluso más, HAProxy (muy maduro y fácilmente compatible con el proxy de sesión pegajosa). Como lo indica @tsturzl, hay un satellite
, pero dado el bajo volumen de descargas, pisaría con cuidado (al menos en un entorno de producción).
Dicho esto, ya que parece que ya tienes todo configurado con Node, la reconstrucción y la nueva arquitectura pueden ser más trabajo de lo que vale la pena. Por lo tanto, para instalar la rama de caronte
con NPM:
Elimine su instalación maestra anterior de
http-node-proxy
connpm uninstall node-proxy
y / osudo npm -d uninstall node-proxy
- Ejecute
npm -g install /path/to/node-http-proxy-caronte
- En mi caso, el enlace de instalación se rompió, así que tuve que ejecutar
sudo npm link http-proxy
Lo tengo en funcionamiento usando su ejemplo de proxy básico, ya sea que esto resuelva o no el problema de las sesiones eliminadas, solo usted lo sabrá.