¿HTML WebSockets mantiene una conexión abierta para cada cliente? ¿Esto escala?

159

Tengo curiosidad por saber si alguien tiene alguna información sobre la escalabilidad de HTML WebSockets. Por todo lo que he leído, parece que cada cliente mantendrá una línea de comunicación abierta con el servidor. Me pregunto cómo se escala y cuántas conexiones WebSocket abiertas puede manejar un servidor. Quizás dejar esas conexiones abiertas no es un problema en realidad, pero parece que lo es.

Ryan Montgomery
fuente
1
No existe tal cosa como un HTML WebSocket. Te refieres a HTTP WebSocket.
Marqués de Lorne

Respuestas:

209

En la mayoría de los casos, WebSockets probablemente escalará mejor que las solicitudes AJAX / HTML. Sin embargo, eso no significa que WebSockets sea un reemplazo para todos los usos de AJAX / HTML.

Cada conexión TCP en sí misma consume muy poco en términos de recursos del servidor. A menudo, configurar la conexión puede ser costoso, pero mantener una conexión inactiva es casi gratis. La primera limitación que generalmente se encuentra es el número máximo de descriptores de archivo (los sockets consumen descriptores de archivo) que se pueden abrir simultáneamente. A menudo, el valor predeterminado es 1024, pero puede configurarse más fácilmente.

¿Alguna vez intentó configurar un servidor web para admitir decenas de miles de clientes simultáneos AJAX? Cambie esos clientes a clientes de WebSockets y podría ser factible.

Las conexiones HTTP, si bien no crean archivos abiertos ni consumen números de puerto durante un período prolongado, son más caras en casi cualquier otro sentido:

  • Cada conexión HTTP lleva una gran cantidad de equipaje que no se usa la mayor parte del tiempo: cookies, tipo de contenido, longitud del contenido, agente de usuario, identificación del servidor, fecha, última modificación, etc. Una vez que se establece una conexión WebSockets, solo el los datos requeridos por la aplicación deben enviarse de un lado a otro.

  • Por lo general, los servidores HTTP están configurados para registrar el inicio y la finalización de cada solicitud HTTP que ocupa el tiempo de disco y CPU. Se volverá estándar registrar el inicio y la finalización de los datos de WebSockets, pero mientras la conexión de WebSockets realice la transferencia dúplex no habrá ninguna sobrecarga de registro adicional (excepto por la aplicación / servicio si está diseñado para hacerlo).

  • Por lo general, las aplicaciones interactivas que usan AJAX sondean continuamente o utilizan algún tipo de mecanismo de sondeo largo. WebSockets es una forma mucho más limpia (y con menos recursos) de hacer un modelo más eventual donde el servidor y el cliente se notifican entre sí cuando tienen algo que informar sobre la conexión existente.

  • La mayoría de los servidores web populares en producción tienen un conjunto de procesos (o subprocesos) para manejar solicitudes HTTP. A medida que aumenta la presión, aumentará el tamaño del grupo porque cada proceso / subproceso maneja una solicitud HTTP a la vez. Cada proceso / subproceso adicional utiliza más memoria y la creación de nuevos procesos / subprocesos es bastante más costoso que la creación de nuevas conexiones de socket (que esos procesos / subprocesos todavía tienen que hacer). La mayoría de los marcos de servidores WebSockets populares siguen la ruta del evento que tiende a escalar y funcionar mejor.

El beneficio principal de WebSockets serán las conexiones de baja latencia para aplicaciones web interactivas. Se escalará mejor y consumirá menos recursos de servidor que HTTP AJAX / long-poll (suponiendo que la aplicación / servidor esté diseñada correctamente), pero la latencia IMO es el beneficio principal de WebSockets porque habilitará nuevas clases de aplicaciones web que no son posibles con la sobrecarga actual y la latencia de AJAX / long-poll.

Una vez que el estándar WebSockets esté más finalizado y tenga un soporte más amplio, tendrá sentido usarlo para la mayoría de las nuevas aplicaciones web interactivas que necesitan comunicarse con frecuencia con el servidor. Para las aplicaciones web interactivas existentes, realmente dependerá de qué tan bien esté funcionando el modelo actual de AJAX / long-poll. El esfuerzo para convertir no será trivial, por lo que en muchos casos el costo no valdrá la pena.

Actualización :

Enlace útil: 600k conexiones websocket concurrentes en AWS usando Node.js

canaca
fuente
44
Impresionante anser. Gracias por tomarte el tiempo de responder.
Ryan Montgomery
77
Sin embargo, todavía no sé cómo escalar una vez que golpeas la pared. Es cierto que WebSockets consume menos recursos (se escalan verticalmente), pero HTTP es ideal para escalar horizontalmente. Teóricamente puedo agregar servidores para escalar infinitamente. Siempre he estado confundido acerca de cómo escalar una vez que usas la capacidad de una sola caja. Pensamientos?
Sean Clark Hess
66
@Sean. WebSockets no es necesariamente peor para escalar horizontalmente. Simplemente abre nuevas aplicaciones que no necesariamente se escalan tan fácilmente. Por ejemplo, para servir datos estáticos, un grupo de servidores WebSocket se escalaría igual de bien (o mejor) que un grupo de servidores HTTP. Un juego en tiempo real de baja latencia es difícil de escalar independientemente del transporte (y simplemente no es realmente factible usando HTTP). La verdadera pregunta es qué tan bien escalan sus datos / aplicaciones. Si que las escalas, entonces su elección de HTTP vs WebSockets debe basarse en otros factores: la latencia, opciones de implementación, soporte de los navegadores, etc.
Kanaka
2
Una corrección: una conexión TCP consta de ip de destino y puerto de destino. Eso significa que el límite de ± 64k puertos es realmente SOLO para un solo cliente. Teóricamente, el servidor puede tener cualquier número de conexiones abiertas, SOLO limitado por su hardware.
Rizon
@Rizon, eso es cierto. Actualicé la respuesta y cambié la limitación de puerto abierto y, en su lugar, mencioné la limitación del descriptor de archivo, que es con la que la gente suele encontrarse primero.
kanaka
36

Solo una aclaración: la cantidad de conexiones de clientes que un servidor puede admitir no tiene nada que ver con los puertos en este escenario, ya que el servidor [típicamente] solo está escuchando conexiones WS / WSS en un solo puerto. Creo que a lo que se referían los otros comentaristas eran descriptores de archivos. Puede establecer el número máximo de descriptores de archivo bastante alto, pero luego debe tener cuidado con los tamaños de búfer de socket que se suman para cada socket TCP / IP abierto. Aquí hay información adicional: /server/48717/practical-maximum-open-file-descriptors-ulimit-n-for-a-high-volume-system

En cuanto a la disminución de la latencia a través de WS vs. HTTP, es cierto ya que no hay más análisis de encabezados HTTP más allá del apretón de manos WS inicial. Además, a medida que se envían más y más paquetes con éxito, la ventana de congestión TCP se amplía, reduciendo efectivamente el RTT.

Miguel
fuente
AFAIR hay un puerto entrante, pero siempre se abre un puerto saliente para cada conexión. De hecho, esto es solo una parte del problema de C10k .
Arnaud Bouchez
14

Cualquier servidor único moderno puede servir a miles de clientes a la vez . Su software de servidor HTTP tiene que estar orientado a eventos (IOCP) (ya no estamos en la antigua conexión Apache one = one thread / process ecuación). Incluso el servidor HTTP integrado en Windows (http.sys) está orientado a IOCP y es muy eficiente (se ejecuta en modo kernel). Desde este punto de vista, no habrá mucha diferencia en el escalado entre WebSockets y la conexión HTTP normal. Una conexión TCP / IP utiliza un pequeño recurso (mucho menos que un subproceso), y los sistemas operativos modernos están optimizados para manejar muchas conexiones concurrentes: WebSockets y HTTP son solo protocolos de capa de aplicación OSI 7, heredados de estas especificaciones TCP / IP.

Pero, por experimento, he visto dos problemas principales con WebSockets:

  1. No son compatibles con CDN;
  2. Tienen posibles problemas de seguridad.

Por lo tanto, recomendaría lo siguiente, para cualquier proyecto:

  • Use WebSockets solo para notificaciones de clientes (con un mecanismo de reserva para sondeo largo; hay muchas bibliotecas disponibles);
  • Use RESTful / JSON para todos los demás datos, usando un CDN o proxies para caché.

En la práctica, las aplicaciones completas de WebSockets no se escalan bien. Simplemente use WebSockets para lo que fueron diseñados: enviar notificaciones del servidor al cliente.

Sobre los posibles problemas del uso de WebSockets:

1. Considere usar un CDN

Hoy (casi 4 años después), el escalado web implica el uso de front-end de Content Delivery Network (CDN), no solo para contenido estático (html, css, js) sino también para los datos de su aplicación (JSON) .

Por supuesto, no colocará todos sus datos en su caché CDN, pero en la práctica, una gran cantidad de contenido común no cambiará con frecuencia. Sospecho que el 80% de sus recursos REST pueden almacenarse en caché ... Incluso un tiempo de espera de caducidad de CDN de un minuto (o 30 segundos) puede ser suficiente para darle a su servidor central una nueva vida y mejorar mucho la capacidad de respuesta de la aplicación, ya que CDN puede estar geográficamente sintonizado ...

Que yo sepa, todavía no hay soporte de WebSockets en CDN, y sospecho que nunca lo sería. Los WebSockets tienen estado, mientras que HTTP no tiene estado, por lo que se almacena en caché con mucha facilidad. De hecho, para que WebSockets sea compatible con CDN, es posible que deba cambiar a un enfoque RESTful sin estado ... que ya no sería WebSockets.

2. Problemas de seguridad

WebSockets tiene posibles problemas de seguridad, especialmente sobre los ataques de DOS. Para obtener una ilustración sobre las nuevas vulnerabilidades de seguridad, consulte este conjunto de diapositivas y este ticket del kit web .

Los WebSockets evitan cualquier posibilidad de inspección de paquetes a nivel de la capa de aplicación OSI 7, que hoy en día es bastante estándar en cualquier seguridad empresarial. De hecho, WebSockets hace que la transmisión se ofusque, por lo que puede ser una violación importante de la fuga de seguridad.

Arnaud Bouchez
fuente
2
@ArnaudBouchez - +1 por la buena exposición en CDN. Pregunta de seguimiento rápida: ¿qué opina de la viabilidad de las redes de entrega de eventos? Diseñado según las CDN, pero orientado a entregar datos de transmisión, etc. a través de sockets web o alguna otra tecnología aún no vista.
Quixver
8

Piénselo de esta manera: lo que es más barato, mantener una conexión abierta o abrir una nueva conexión para cada solicitud (con la sobrecarga de negociación de hacerlo, recuerde que es TCP).

Por supuesto, depende de la aplicación, pero para las conexiones en tiempo real a largo plazo (por ejemplo, un chat AJAX) es mucho mejor mantener la conexión abierta.

El número máximo de conexiones estará limitado por el número máximo de puertos libres para los sockets.

kaoD
fuente
Puede mantener la conexión abierta sin usar un WebSocket (gracias a la opción mantener vivo de HTTP / 1.1). No estoy seguro de entender tu punto aquí.
Arnaud Bouchez
1
+1. La gente tiende a olvidar que configurar una conexión TCP implica un syn / ack / ack y TLS requiere más viajes de ida y vuelta para el intercambio de claves.
quixver
1
@ArnaudBouchez verifique en.wikipedia.org/wiki/HTTP_persistent_connection#HTTP_1.1 Los WebSockets están abiertos todo el tiempo que desee y no son hack (como las encuestas largas y otras alternativas).
kaoD
-5

No, no escala, da un trabajo tremendo a los conmutadores de rutas intermedias. Luego, en el lado del servidor, las fallas de la página (debe mantener todos esos descriptores) están alcanzando valores altos, y aumenta el tiempo para llevar un recurso al área de trabajo. Estos son en su mayoría servidores escritos en JAVA y podría ser más rápido mantener esos millones de sockets que destruir / crear uno. Cuando ejecuta dicho servidor en una máquina, cualquier otro proceso ya no puede moverse.

usuario2195463
fuente