¿Por qué se acepta el sondeo en la programación web?

108

Actualmente estoy trabajando en un proyecto de Ruby on Rails que muestra una lista de imágenes.

Una herramienta imprescindible para este proyecto es que muestra nuevas publicaciones en tiempo real sin la necesidad de actualizar la página web. Después de buscar por un tiempo, me topé con algunas soluciones y servicios de JavaScript como PubNub; sin embargo, ninguna de las soluciones proporcionadas tenía sentido en absoluto.

En la solución de JavaScript ( sondeo ) sucede lo siguiente:

  • El usuario 1 ve la lista de fotos.
  • En segundo plano, el código JavaScript está sondeando un punto final cada segundo para ver si hay una nueva publicación.
  • El usuario 2 agrega una nueva foto.
  • Hay un retraso de 50 ms antes de que se active el nuevo ciclo y obtenga los nuevos datos.
  • El nuevo contenido se carga en el DOM .

Esto parece extraño cuando se traduce a un ejemplo del mundo real:

  • El usuario 1 sostiene una pila de imágenes en su escritorio.
  • Él / ella camina hacia el fotógrafo cada segundo y le pregunta si tiene uno nuevo.
  • El fotógrafo hace una nueva foto.
  • Este segundo cuando él / ella entra, ella puede tomar la foto y ponerla en la pila.

En mi opinión, la solución debería ser la siguiente:

  • El usuario 1 sostiene una pila de imágenes en su escritorio.
  • El fotógrafo toma una nueva foto.
  • El fotógrafo camina hacia el montón y lo pone con el resto.

La solución PubNub es básicamente la misma, sin embargo, esta vez hay un pasante interno entre las partes para compartir los datos.

No hace falta decir que ambas soluciones consumen mucha energía, ya que se activan incluso cuando no hay datos para cargar.

Hasta donde yo sé, no hay una explicación (lógica) de por qué esta forma de implementación se utiliza en casi todas las aplicaciones en tiempo real.

dennis
fuente
195
Ignorando por un momento que los navegadores web no son servidores que pueden recibir conexiones entrantes ... espere, no, no ignoremos eso.
GrandmasterB
17
@dennis: una conexión con estado y persistente entre el servidor y el cliente probablemente eliminaría la necesidad de sondeo, pero no es así como se diseñó la Web.
FrustratedWithFormsDesigner
58
¿Qué hay de Websockets?
I.devries
25
O eche un vistazo a las encuestas largas. Básicamente, usted encuesta, pero el servidor no responde antes de que tenga datos nuevos que mostrarle.
Matsemann
53
Hay muchas soluciones y algoritmos perfectamente sensibles en el espacio de la computadora que serían completamente absurdos en el espacio de la carne.
whatsisname

Respuestas:

179

Empujar funciona bien para 1 o un número limitado de usuarios.

Ahora cambie el escenario con un fotógrafo y 1000 usuarios que desean una copia de la imagen. El fotógrafo tendrá que caminar hasta 1000 montones. Algunos de ellos pueden estar en una oficina cerrada o esparcidos por todo el piso. O su usuario de vacaciones, y no está interesado en nuevas fotos en este momento.

El fotógrafo estaría ocupado caminando todo el tiempo y no tomaría nuevas fotos.

Fundamentalmente: un modelo de extracción / sondeo se adapta mejor a muchos lectores poco confiables con requisitos flexibles en tiempo real (si una imagen tarda 10 segundos en llegar a una pila, ¿cuál es el problema?)

Dicho esto, un modelo push es aún mejor en muchas situaciones. Si necesita baja latencia (necesita esa nueva foto 5s después de que se toma), o las actualizaciones son raras y las solicitudes son frecuentes y predecibles (siga preguntando al fotógrafo cada 10 segundos cuando genera una nueva imagen al día), entonces tirar es inapropiado. Depende de lo que intentes hacer. NASDAQ: empuje. Servicio meteorológico: pull. Fotógrafo de bodas: probablemente tire. Agencia de fotografía de noticias: probablemente empuje.

ptyx
fuente
32
Realmente me gusta tu analogía con 1000 usuarios, algunos de vacaciones, otros no interesados. +1.
riwalk
44
@EsbenSkovPedersen: el límite de socket no se debe a la dirección IP. Se debe al descriptor de archivo abierto máximo. Por lo tanto, la cantidad máxima de socket abierto es independiente de la cantidad de direcciones IP que use.
slebetman
10
Esta es una analogía horrible para decirlo suavemente. Para que el empuje funcione, el cliente de cualquier usuario debe mantener una conexión abierta de algún tipo. De hecho, el sondeo es una emulación de una conexión. No es como porque algunos clientes están encuestando, que todos los clientes sean notificados. De manera similar, cuando algunos clientes abren una conexión para notificaciones push, no todos los clientes son notificados. Este es un consejo muy pobre que invita a tirar recursos por la ventana. Ser bombardeado con 10000 solicitudes por segundo prácticamente nunca es más barato o mejor que mantener 10000 tomas abiertas.
back2dos
8
@ptyx: el intervalo de 1s es el que se está discutiendo aquí. 10k solicitudes por segundo significa 10k apretones de manos TCP y 10k solicitudes HTTP (cada una de ellas alcanza fácilmente 2KB), lo que le brinda múltiples órdenes de magnitud más ruido de fondo golpeando su servidor. Existe una variedad de bibliotecas probadas en batalla que hacen que las suscripciones push sean tan fáciles como implementar encuestas. Incluso hay marcos como meteor.js que abstraen completamente todo el problema. Apelar a la escalabilidad sin ninguna explicación adicional tampoco es un argumento. De todos modos, he expresado mis dudas y no deseo comenzar una discusión;)
back2dos
55
Estoy de acuerdo con el comentario de back2dos anterior. Si pull escalara mejor que push, google, stack exchange, facebook, servicios de acciones en línea, etc. utilizarían la tecnología pull. Pero ellos no. Básicamente, martillar el servidor en lugar de configurar una estación de escucha escala enormemente. Los principales servicios evitan las encuestas.
Travis J
106

Estoy realmente sorprendido de que solo una persona haya mencionado WebSockets . El soporte se implementa básicamente en todos los principales navegadores .

De hecho, PubNub los usa. Para su aplicación, el navegador probablemente se suscribirá a un socket que se emitirá cada vez que haya una nueva foto disponible. El socket no enviaría la foto, eso sí, sino solo un enlace para que el navegador pueda descargarla de forma asincrónica.

En su ejemplo, imagine algo como:

  1. Los usuarios le permiten al fotógrafo saber que quiere saber sobre todas las fotos futuras
  2. El fotógrafo dice a través del altavoz que hay una nueva foto disponible
  3. El usuario le pide una foto al fotógrafo

Esto es algo así como su solución de ejemplo original. Es más eficiente que el sondeo porque el cliente no tiene que enviar ningún dato al servidor (excepto tal vez latidos ).

Además, como otros han mencionado, existen otros métodos que son mejores que el simple sondeo que funcionan en navegadores antiguos ( longpolling, et al .)

korylprince
fuente
43
@RobertHarvey, ¿por qué WebSockets no están relacionados con la pregunta? La pregunta se pregunta si el sondeo es una estrategia aceptable, y hoy en día claramente no es aceptable (o al menos no es óptimo). WebSockets, los eventos enviados por el servidor y las encuestas largas funcionan mucho mejor en prácticamente todos los casos de uso.
Fabrício Matté
77
@RobertHarvey, esa fue solo mi interpretación, sin reenmarcar hasta donde puedo ver. Claro, la pregunta es por qué todavía se acepta y no cuál es la estrategia óptima , pero todavía están estrechamente relacionadas.
Fabrício Matté
25
WebSockets (y similares) son lo más cercano que puede llegar a implementar la "solución" del OP, por lo que creo que es muy relevante a pesar de que no lo menciona específicamente.
korylprince
66
Sin mencionar que los StackExchangesitios como el que estás usando ahora (a menos que estés mirando esta página web en caché / guardada) usan WebSockets. Por eso también me preguntaba por qué nadie hasta que @korylprince mencionó WebSockets.
trysis
66
@ FabrícioMatté: en realidad, no todos los casos de uso. El sondeo largo requiere mantener abierto un socket para todos los usuarios que utiliza recursos del sistema. Los servicios de Fr que no requieren mucho tiempo pero que tienen muchos usuarios, mantener un socket abierto suele ser más costoso que dar servicio a un 304 corto de vez en cuando. Para la mayoría de los servicios, un ligero retraso no es un problema. Una sola máquina generalmente puede servir a más clientes con sondeo que con empuje.
Lie Ryan
42

A veces lo suficientemente bueno es lo suficientemente bueno.

De todas las formas posibles de implementar un proceso de comunicaciones "en tiempo real", la encuesta es quizás la forma más sencilla. El sondeo se puede usar de manera efectiva cuando el intervalo de sondeo es relativamente largo (es decir, segundos, minutos u horas en lugar de instantáneo), y los ciclos de reloj consumidos al verificar la conexión o el recurso realmente no importan.

Robert Harvey
fuente
3
Esto, mil veces esto. Se acepta porque generalmente es lo suficientemente bueno.
corsiKa
1
Esa es una respuesta lo suficientemente buena
Zain R
31

El protocolo HTTP está limitado en que el cliente DEBE ser el que inicie la solicitud. El servidor no puede comunicarse con el cliente a menos que responda a la solicitud de un cliente.

Entonces, para ajustar su ejemplo del mundo real, agregue la siguiente restricción:

  • El usuario 2 SOLO puede responder a las preguntas del usuario 1 con una respuesta de una sola oración, después de lo cual el usuario 1 debe irse. El usuario 2 no tiene otra forma de comunicarse.

Con esta nueva restricción, ¿cómo lo haría además de las encuestas?

Riwalk
fuente
66
HTTP 2.0 admitirá los empujes del servidor. "Empujar permite a los servidores enviar representaciones a los clientes sin que se haga una solicitud explícita". en.wikipedia.org/wiki/HTTP_2.0
kaptan
55
@kaptan, eso es genial, pero no está disponible. Haz las paces con lo que tienes.
riwalk
77
También hay encuestas de larga duración que están disponibles en este momento y simulan un modelo push usando un pull.
Tim B
24
@dennis: Después de haber escrito un software de automatización industrial, me gustaría comentar su ejemplo de sondeo de sensores. Los sensores de sondeo tienen dos propósitos: el más obvio es obtener nuevos datos. Lo menos obvio es detectar que el sensor aún está vivo, no se bloqueó debido a un error o se quemó debido al incendio de la fábrica o se derritió debido a un accidente industrial. El silencio, el hecho de que no recibas respuesta, también son datos valiosos.
slebetman
3
Los sensores @dennis a menudo detectan mucho más rápido de lo que le interesan los datos. El sondeo le permite obtener el valor del sensor exactamente cuando lo desee, sin verse inundado de actualizaciones que no le interesan. (Imagínese si el sistema operativo notifica su aplicación cada vez que un archivo ha cambiado en cualquier lugar en el disco, en lugar de su aplicación necesidad de abrir y leer el archivo)
immibis
13

¿Por qué se acepta la votación? ¡Porque en realidad todas las soluciones son encuestas de bajo nivel!

Si el servidor debe actualizarlo tan pronto como haya nuevas imágenes disponibles, generalmente debe tener una conexión con usted, porque las direcciones IP cambian con frecuencia y nunca se sabe si alguien ya no está interesado, por lo que el cliente debe enviar algún tipo de señal de mantener vivo, por ejemplo, "Todavía estoy aquí, no estoy fuera de línea"

Todas las conexiones con estado (por ejemplo, TCP / IP) funcionan igual, ya que solo puede enviar paquetes de datos singulares a través de Internet; nunca se sabe si la otra parte sigue ahí.

Entonces cada protocolo tiene un tiempo de espera. Si una entidad no responde dentro de X segundos, se presume que está muerta. Entonces, incluso si solo tiene una conexión abierta entre el servidor y el cliente, sin enviar ningún dato, el servidor y el cliente deben enviar paquetes regulares de mantenimiento (esto se maneja a bajo nivel si abre una conexión entre ellos), y cómo es Esto al final es diferente de las encuestas?

Entonces, el mejor enfoque probablemente sería longpolling:

El cliente envía una solicitud inmediatamente después de cargar el sitio (por ejemplo, diciéndole al fotógrafo "Dime si hay nuevas imágenes"), pero el servidor no responde si no hay nuevas imágenes. Tan pronto como se agota el tiempo de la solicitud, el cliente vuelve a preguntar.

Si el servidor ahora tiene nuevas imágenes, puede responder de inmediato a todos los clientes que hacen cola para obtener nuevas imágenes. Por lo tanto, su tiempo de reacción después de una nueva imagen es aún más corto que con la inserción, ya que el cliente todavía está esperando una respuesta abierta y no tiene que establecer una conexión con el cliente. ¡Y las solicitudes de sondeo del cliente no son mucho más tráfico que una conexión constante entre el cliente y el servidor para obtener una respuesta!

Falco
fuente
No estoy de acuerdo con que cada solución termine siendo un sondeo de bajo nivel. Está confundiendo el sondeo requerido para enviar datos con el sondeo requerido para saber cuándo se pierde un cliente. Sí, este último siempre terminará sondeando en algún lugar de la pila de protocolos, pero eso puede ser a una frecuencia muy baja (como una vez cada cinco minutos), mientras que sondear datos reales cada segundo es un desperdicio que PUEDE evitarse con notificaciones push verdaderas eso NO está sondeando en ningún nivel de la pila.
Allon Guralnek
Primero, la mayoría de los paquetes de keepalive se ejecutan a una frecuencia bastante alta, porque desea evitar intervalos de tiempo de espera comunes, por lo que pocos segundos no son infrecuentes para TCP / IP y casi cualquier cosa que no use tcp puede estar bloqueada por firewalls. Entonces, cuando necesito enviar un paquete de datos cada X segundos, ¿por qué no llenarlo con algunos datos prácticamente sin costo?
Falco
1
@Guralnek, incluso si tuviera una conexión con un intervalo de mantenimiento de 5 minutos, el tiempo de espera sería mayor, ya que debe agregar el retraso real y los paquetes perdidos. Y el servidor mantendría muchas conexiones durante 5 minutos después de que los clientes se hayan desconectado, por lo que, en general, esto probablemente costará más recursos del servidor y ahorrará solo un ancho de banda mínimo
Falco
1
+1 para encuestas largas. Busque el cometa en.wikipedia.org/wiki/Comet_%28programming%29
Zan Lynx
9

Una ventaja de las encuestas es que limita el daño que se puede causar si un mensaje se pierde o el estado de algo falla. Si X le pregunta a Y su estado una vez cada cinco segundos, entonces la pérdida de una solicitud o una respuesta simplemente dará como resultado que la información de X esté desactualizada en diez segundos en lugar de 5. Si Y se reinicia, X puede averiguarlo al siguiente tiempo Y puede responder a uno de los mensajes de X. Si se reinicia X, puede que nunca se moleste en pedirle nada a Y después, pero quien esté observando el estado de X debería reconocer que se ha reiniciado.

Si en lugar de X sondeando Y, X confiaba en Y para informarlo cada vez que cambiaba su estado, entonces si el estado de Y cambiaba y enviaba un mensaje a X, pero por cualquier razón ese mensaje no fue recibido, X podría nunca darse cuenta del cambio . Del mismo modo, si Y se reinicia y nunca tiene ningún motivo para enviar a X un mensaje sobre algo.

En algunos casos, puede ser útil que X solicite que Y envíe mensajes de forma autónoma con su estado, ya sea periódicamente o cuando cambie, y que solo tenga una encuesta X si pasa demasiado tiempo sin escuchar nada de Y. Tal diseño puede eliminar el necesita que X envíe la mayoría de sus mensajes (por lo general, X debería informar al menos ocasionalmente a Y de que todavía está interesado en recibir mensajes, e Y debería dejar de enviar mensajes si transcurre demasiado tiempo sin ninguna indicación de interés). Tal diseño, sin embargo, requeriría que Y persistentementemantener información sobre X, en lugar de poder simplemente enviar una respuesta a quien lo encuestó y luego olvidarse inmediatamente de quién era. Si Y es un sistema integrado, tal simplificación puede ayudar a reducir los requisitos de memoria lo suficiente como para permitir el uso de un controlador más pequeño y más barato.

El sondeo puede tener una ventaja adicional cuando se utiliza un medio de comunicación potencialmente poco confiable (por ejemplo, UDP o radio): puede eliminar en gran medida la necesidad de acuses de recibo de la capa de enlace. Si X envía a Y una solicitud de estado Q, Y responde con un informe de estado R, y X escucha a R, X no necesitará escuchar ningún tipo de reconocimiento de capa de enlace para que Q sepa que se recibió. Por el contrario, una vez que Y envía a R, no necesita saber ni preocuparse si X lo recibió. Si X envía una solicitud de estado y no obtiene respuesta, puede enviar otra. Si Y envía un informe y X no lo escucha, X enviará otra solicitud. Si cada solicitud se envía una vez y produce una respuesta o no, ninguna de las partes necesita saber o importar si se recibió algún mensaje en particular. Dado que enviar un acuse de recibo puede consumir casi tanto ancho de banda como una solicitud o informe de estado, el uso de un viaje de ida y vuelta de solicitud-informe no cuesta mucho más de lo que costaría un informe y acuse de recibo no solicitado Si X envía algunas solicitudes sin obtener respuestas, es posible que en algunas redes enrutadas dinámicamente necesite habilitar confirmaciones de nivel de enlace (y solicitar en su solicitud que Y haga lo mismo) para que la pila de protocolos subyacente pueda reconocer el problema de entrega y buscar una nueva ruta, pero cuando las cosas están funcionando, un modelo de solicitud-informe será más eficiente que usar los reconocimientos a nivel de enlace.

Super gato
fuente
El problema del que habla con Y al enviar mensajes a X (segundo párrafo) se puede solucionar con un número de serie adjunto a cada mensaje. Si se pierde un mensaje, X lo sabrá porque no recibió esa serie. En ese punto, puede tomar otras medidas para sincronizarse con Y. DNS master -> replicación esclava funciona de esta manera.
korylprince
@korylprince: Cualquiera de las partes puede averiguar sobre el mensaje que falta si la otra parte tiene la oportunidad de enviar algo (y lo hace con éxito), o si tiene motivos para esperar algo del otro lado y nunca lo recibe. Si un lado envía una actualización de estado y no requiere acuses de recibo o se da por vencido después de volver a intentarlo varias veces, y el otro lado no espera transmisiones programadas, el otro lado no sabrá que la conexión ha desaparecido.
supercat
2
@korylprince: el problema es que, sin mensajes periódicos, X puede detectar el mensaje que falta un día tarde o un año tarde o 10 años tarde. Para detectar el paquete perdido en un tiempo razonable, de alguna manera necesita sondear. Puede "sacar" la encuesta o puede "empujar" la encuesta. El primero se llama "votación", el segundo se llama "latido del corazón"
slebetman
Ambos muy cierto. Todo depende de la situación.
korylprince
@slebetman: Sin mensajes periódicos, si Y se reinicia, puede haber ningún mecanismo por el cual X sería jamás descubrirlo.
supercat
1

La pregunta es equilibrar la cantidad de encuestas innecesarias frente a la cantidad de impulsos innecesarios.

Si encuesta:

  • Obtienes una respuesta en este mismo momento. Bien si solo pregunta ocasionalmente o necesita un conjunto de datos en este mismo momento.
  • Es posible que obtenga una respuesta "sin contenido", lo que provocará una carga inútil en la línea.
  • Usted pone carga en la línea solo cuando sondea, pero siempre cuando sondea.

Si empujas:

  • Entrega la respuesta correcta cuando está disponible, lo que permite un procesamiento inmediato en el lado del cliente.
  • Es posible que entregue datos a clientes que no estén interesados ​​en estos datos, causando una carga inútil en la línea.
  • Pones carga en la línea cada vez que hay nuevos datos, pero solo cuando hay nuevos datos.

Hay varias soluciones sobre cómo lidiar con los diversos escenarios y sus desventajas, como por ejemplo un tiempo mínimo entre encuestas, proxies solo de sondeo para quitar la carga del sistema principal o, para los empujones, una regulación para registrar y especificar los datos deseados seguidos de anulación del registro al cerrar sesión. Cuál se ajusta mejor no es nada que pueda decir en general, depende del sistema.

En su ejemplo, el sondeo no es la solución más eficiente, sino la más práctica. Es muy fácil escribir un sistema de sondeo en JavaScript, y también es muy fácil implementarlo en el lado de entrega. Un servidor hecho para entregar datos de imágenes debería poder manejar las solicitudes adicionales, y si no, se puede escalar linealmente, ya que los datos son en su mayoría estáticos y, por lo tanto, se pueden almacenar en caché fácilmente.

Un método de inserción que implemente un inicio de sesión, una descripción de los datos deseados y, finalmente, un cierre de sesión sería más eficiente, pero probablemente sea demasiado complejo para el "script kiddy" promedio, y debe abordar la pregunta: ¿qué pasa si el usuario solo cierra el navegador y no se puede cerrar la sesión?

¿Quizás es mejor tener más usuarios (ya que el acceso es fácil) que ahorrar dinero en otro servidor de caché?

TwoThe
fuente
1

Por alguna razón, en estos días, todos los desarrolladores web más jóvenes parecen haber olvidado las lecciones del pasado y por qué algunas cosas han evolucionado de la manera en que lo hicieron.

  1. El ancho de banda fue un problema
  2. La conexión puede ser intermitente.
  3. Los navegadores no tenían tanta potencia informática
  4. Había otros métodos para acceder al contenido. La web no es w3.

Ante estas restricciones, es posible que no tenga una comunicación constante de 2 vías. Y si observa el modelo OSI, encontrará que la mayoría de las consideraciones están destinadas a desacoplar la persistencia con la conexión subyacente.

Con eso en mente, un método de sondeo para extraer información es una excelente manera de reducir el ancho de banda y la computación en el lado del cliente. El aumento de empuje es en su mayor parte solo el cliente que realiza sondeos constantes o sockets web. Personalmente, si fuera todos los demás, agradecería la regularidad de las encuestas como un medio de análisis de tráfico, donde una solicitud GET / POST fuera de tiempo señalaría a un hombre en una situación intermedia de algún tipo.

Cuenta de invitado
fuente