Pregunta

Estamos trabajando en una aplicación Ruby on Rails que debe aprovechar las websockets HTML5. En este momento, tenemos dos "servidores" separados, por así decirlo: nuestra aplicación principal que se ejecuta en Nginx+Passenger y un servidor separado usando Pratik Naik's Calambre marco (que se ejecuta en Delgada) para manejar las conexiones WebSocket.

Idealmente, cuando llegue el momento de la implementación, tendríamos la aplicación Rails ejecutándose en Nginx+Passenger, y el servidor WebSocket estaría proxy detrás de NGINX, por lo que no necesitaríamos que el servidor WebSocket se ejecute en un puerto diferente.

El problema es, en esta configuración, parece que Nginx está cerrando las conexiones con delgadas demasiado temprano. La conexión se establece correctamente al servidor delgado, luego se cierre inmediatamente con un código de respuesta de 200. Suponemos que NGINX no se da cuenta de que el cliente está tratando de establecer una conexión de larga duración para el tráfico de WebSocket.

Es cierto que no soy tan inteligente con la configuración Nginx, entonces, ¿es posible configurar NGINX para actuar como un proxy inverso para un servidor WebSocket? ¿O tengo que esperar a que NGINX ofrezca soporte para las nuevas cosas de WebSocket Handshake? Suponiendo que tener tanto el servidor de aplicaciones como el servidor WebSocket escuchando en el puerto 80 es un requisito, ¿eso significa que tengo que tener una ejecución delgada en un servidor separado sin NGINX por ahora?

Gracias de antemano por cualquier consejo o sugerencia. :)

-John

¿Fue útil?

Solución

No puedes usar Nginx para esto actualmenteya no es cierto, pero sugeriría mirar a Haproxy. Lo he usado para exactamente este propósito.

El truco es establecer tiempos de espera largos para que las conexiones del socket no estén cerradas. Algo como:

timeout client  86400000 # In the frontend
timeout server  86400000 # In the backend

Si desea servir, digamos una aplicación de rieles y calambres en el mismo puerto, puede usar reglas de ACL para detectar una conexión WebSocket y usar un backend diferente. Entonces su configuración de frontend de haproxy se vería algo así como

frontend all 0.0.0.0:80
  timeout client    86400000
  default_backend   rails_backend
  acl websocket hdr(Upgrade)    -i WebSocket
  use_backend   cramp_backend   if websocket

Para completar el backend se vería

backend cramp_backend
  timeout server  86400000
  server cramp1 localhost:8090 maxconn 200 check

Otros consejos

¿Qué tal usar mi módulo nginx_tcp_proxy_module?

Este módulo está diseñado para proxy TCP general con Nginx. Creo que también es adecuado para WebSocket. Y solo agrego TCP_SSL_MODULE en la rama de desarrollo.

nginx (> = 1.3.13) ahora admite WebSockets de proxy inverso.

# the upstream server doesn't need a prefix! 
# no need for wss:// or http:// because nginx will upgrade to http1.1 in the config below
upstream app_server {
    server localhost:3000;
}

server {
    # ...

    location / {
        proxy_pass http://app_server;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_redirect off;
    }
}

Fuera de la caja (es decir, fuentes oficiales) Nginx puede establecer solo conexiones HTTP 1.0 a un ascensor (= backend), lo que significa que no es posible que no sea posible: Nginx seleccionará un servidor ascendente, abrirá conexión a él, proxy, caché (si lo desea ) y cierre la conexión. Eso es todo.

Esta es la razón fundamental de la razón que los marcos que requieren conexiones persistentes al backend no funcionarían a través de Nginx (sin HTTP/1.1 = Sin Keepalive y sin WebSockets, supongo). A pesar de tener esta desventaja, hay un beneficio evidente: Nginx puede elegir de varios ascensores (balance de carga) y conmutación por error de vida uno en caso de que algunos de ellos fallaran.

Editar: NGINX admite HTTP 1.1 a Backends & KeepAlive desde la versión 1.1.4. Se admiten "Fastcgi" y "proxy" ascendentes. Aquí está los documentos

Para cualquier persona que se pregunte sobre el mismo problema, Nginx ahora es oficialmente admite HTTP 1.1 aguas arriba. Consulte la documentación de Nginx para "Keepalive" y "proxy_http_version 1.1".

¿Qué tal Nginx con el nuevo módulo de push HTTP: http://pushmodule.slact.net/. Se encarga del malabarismo de la conexión (por así decirlo) que uno podría tener que preocuparse con un proxy inverso. Sin duda, es una alternativa viable a WebSockets que aún no están completamente en la mezcla. Sé que el desarrollador del módulo Push HTTP todavía está funcionando en una versión totalmente estable, pero está en desarrollo activo. Hay versiones que se utilizan en bases de código de producción. Para citar al autor, "una herramienta útil con un nombre aburrido".

Utilizo NGINX para revertir el proxy a un servidor de estilo Comet con largas conexiones de votación y funciona muy bien. Asegúrese de configurar proxy_send_timeout y proxy_read_timeout a los valores apropiados. También asegúrese de que su servidor de back-end que NGINX esté proxyer para admitir HTTP 1.0 porque no creo que el módulo proxy de NGINX haga HTTP 1.1 todavía.

Solo para aclarar cierta confusión en algunas de las respuestas: KeepAlive permite que un cliente reutilice una conexión para enviar otra solicitud HTTP. No tiene nada que ver con las largas conexiones de encuestas o de mantenimiento abiertas hasta que ocurra un evento, que es lo que estaba haciendo la pregunta original. Por lo tanto, no importa que el módulo proxy de Nginx solo admite HTTP 1.0 que no tiene KeepAlive.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top