Perché il polling è accettato nella programmazione web?


108

Attualmente sto lavorando a un progetto Ruby on Rails che mostra un elenco di immagini.

Un must per questo progetto è che mostra nuovi post in tempo reale senza la necessità di aggiornare la pagina web. Dopo aver cercato per un po ', mi sono imbattuto in alcune soluzioni e servizi JavaScript come PubNub; tuttavia, nessuna delle soluzioni fornite aveva senso.

Nella soluzione JavaScript ( polling ) si verifica quanto segue:

  • L'utente 1 visualizza l'elenco di foto.
  • In background il codice JavaScript esegue il polling di un endpoint ogni secondo per vedere se è presente un nuovo post.
  • L'utente 2 aggiunge una nuova foto.
  • C'è un ritardo di 50 ms prima che il nuovo ciclo venga attivato e recuperi i nuovi dati.
  • Il nuovo contenuto viene caricato nel DOM .

Sembra strano quando tradotto in un esempio del mondo reale:

  • L'utente 1 tiene una pila di immagini sulla sua scrivania.
  • Cammina dal fotografo ogni secondo e gli chiede se ne ha uno nuovo.
  • Il fotografo fa una nuova foto.
  • Questo secondo, quando entra, può scattare la foto e metterla sulla pila.

Secondo me la soluzione dovrebbe essere la seguente:

  • L'utente 1 tiene una pila di immagini sulla sua scrivania.
  • Il fotografo scatta una nuova foto.
  • Il fotografo cammina verso il mucchio e lo mette con il resto.

La soluzione PubNub è sostanzialmente la stessa, tuttavia questa volta c'è un tirocinante che cammina tra le parti per condividere i dati.

Inutile dire che entrambe le soluzioni consumano molto energia in quanto vengono attivate anche quando non ci sono dati da caricare.

Per quanto ne so, non esiste una spiegazione (logica) del perché questo modo di implementazione viene utilizzato in quasi tutte le applicazioni in tempo reale.


195
Ignorando per un momento che i browser Web non sono server in grado di ricevere connessioni in entrata ... aspetta, no, non ignorarlo.
GrandmasterB

17
@dennis: una connessione stateful e persistente tra il server e il client probabilmente eliminerebbe la necessità del polling, ma non è così che è stato progettato il Web.
FrustratedWithFormsDesigner,

58
Che ne dici di Websocket?
I.devries

25
O dai un'occhiata al lungo sondaggio. Fondamentalmente fai il polling, ma il server non risponde prima di avere nuovi dati da mostrarti.
Matsemann,

53
Ci sono molte soluzioni e algoritmi perfettamente sensati nello spazio del computer che sarebbe completamente assurdo fare nello spazio della carne.
whatsisname

Risposte:


179

Il push funziona bene per 1 o per un numero limitato di utenti.

Ora cambia lo scenario con un fotografo e 1000 utenti che vogliono tutti una copia dell'immagine. Il fotografo dovrà camminare fino a 1000 pile. Alcuni di loro potrebbero essere in un ufficio chiuso a chiave o sparsi sul pavimento. O il loro utente in vacanza, e al momento non interessato a nuove foto.

Il fotografo sarebbe sempre impegnato a camminare e non fare nuove foto.

Fondamentalmente: un modello pull / poll si adatta meglio a molti lettori inaffidabili con requisiti in tempo reale sciolti (se un'immagine impiega 10 secondi dopo per arrivare su una pila, qual è il grosso problema).

Detto questo, un modello push è ancora meglio in molte situazioni. Se hai bisogno di una bassa latenza (hai bisogno di quella nuova foto 5s dopo che è stata scattata), o gli aggiornamenti sono rari e richiedono frequenti e prevedibili (continua a chiedere al fotografo ogni 10 secondi quando genera una nuova foto al giorno), quindi tirare è inappropriato. Dipende da cosa stai cercando di fare. NASDAQ: push. Servizio meteorologico: tirare. Fotografo di matrimoni: probabilmente tirare. Agenzia fotografica di notizie: probabilmente spinge.


32
Mi piace molto la tua analogia con 1000 utenti, alcuni in vacanza, altri non interessati. +1.
riwalk

4
@EsbenSkovPedersen: il limite del socket non è dovuto all'indirizzo IP. È dovuto al massimo descrittore di file aperto. Pertanto, il numero massimo di socket aperti è indipendente dal numero di indirizzi IP utilizzati.
Slebetman,

10
Questa è un'analogia orribile per dirla in parole povere. Affinché il push funzioni, il client di qualsiasi utente deve mantenere una connessione aperta di qualche tipo. In effetti, il polling è un'emulazione di una connessione. Non è perché alcuni client eseguono il polling, che tutti i client vengono avvisati. Allo stesso modo, quando alcuni client aprono una connessione per le notifiche push, non tutti i client vengono avvisati. Questo è un consiglio molto scarso che invita a lanciare risorse fuori dalla finestra. Essere bombardati con 10000 richieste al secondo non è praticamente mai più economico o comunque meglio che mantenere 10000 socket aperti.
back2dos,

8
@ptyx: l'intervallo 1s è quello in discussione qui. 10k richieste al secondo indicano 10k TCP handshake e 10k richieste HTTP (ciascuna facilmente raggiungibile 2KB), che ti dà più ordini di grandezza più rumore di fondo che martella il tuo server. Esiste una varietà di librerie testate in battaglia che rendono gli abbonamenti push semplici come mettere in atto il polling. Ci sono persino framework come meteor.js che astraggono completamente l'intero problema. Fare appello alla scalabilità senza ulteriori spiegazioni non è certo un argomento. Comunque, ho espresso i miei dubbi e non desidero iniziare una discussione;)
back2dos

5
Sono d'accordo con il commento di back2dos sopra. Se pull ridimensionato meglio di push, google, stack exchange, facebook, servizi stock online, ecc. Utilizzerebbe la tecnologia pull. Ma loro no. Fondamentalmente, martellare il server invece di impostare una stazione di ascolto si ridimensiona terribilmente. I principali servizi evitano il polling.
Travis J,

106

Sono davvero sorpreso che solo una persona abbia menzionato WebSocket . Il supporto è implementato praticamente in tutti i principali browser .

In effetti PubNub li usa. Per la tua applicazione, il browser si iscriverebbe probabilmente a un socket che trasmetterà ogni volta che una nuova foto è disponibile. Il socket non invierebbe la foto, intendiamoci, ma solo un link in modo che il browser possa scaricarla in modo asincrono.

Nel tuo esempio immagina qualcosa di simile:

  1. Gli utenti informano il fotografo che desidera conoscere tutte le foto future
  2. Il fotografo dice tramite l'altoparlante che è disponibile una nuova foto
  3. L'utente chiede al fotografo una foto

Questo è un po 'come la tua soluzione di esempio originale. È più efficiente del polling perché il client non deve inviare alcun dato al server (tranne forse i battiti del cuore ).

Inoltre, come altri hanno già detto, esistono altri metodi migliori del semplice polling che funzionano nei browser più vecchi ( longpolling, et al .)


43
@RobertHarvey come mai i WebSocket non sono collegati alla domanda? La domanda si chiede se il polling sia una strategia accettabile e al giorno d'oggi chiaramente non è accettabile (o almeno non ottimale). WebSocket, gli eventi inviati dal server e il polling lungo hanno prestazioni molto migliori praticamente in ogni singolo caso d'uso.
Fabrício Matté,

7
@RobertHarvey è stata solo una mia interpretazione, nessuna riformulazione per quanto posso vedere. Certo, la domanda si è chiesta perché è ancora accettata e non quale sia la strategia ottimale , ma questi sono ancora strettamente correlati.
Fabrício Matté,

25
I WebSocket (e simili) sono i più vicini che puoi ottenere per implementare la "soluzione" del PO, quindi penso che sia molto rilevante nonostante lui non ne abbia parlato in modo specifico.
korylprince,

6
Per non parlare dei StackExchangesiti come quello in cui ti trovi adesso (a meno che tu non stia guardando questa pagina web memorizzata nella cache / salvata) usano WebSockets. Questo è il motivo per cui mi chiedevo anche perché nessuno prima di @korylprince menzionato WebSockets.
trysis,

6
@ FabrícioMatté: in realtà, non tutti i casi d'uso. Il polling lungo richiede un socket aperto per tutti gli utenti che occupano risorse di sistema. Per i servizi che non sono molto critici in termini di tempo ma che hanno molti utenti, mantenere una presa aperta è generalmente più costoso rispetto alla manutenzione di un breve 304 di tanto in tanto. Per la maggior parte dei servizi, un leggero ritardo non è un problema. Una singola macchina in genere può servire più client con polling che con push.
Lie Ryan,

42

A volte abbastanza buono è abbastanza buono.

Di tutti i modi possibili per implementare un processo di comunicazione "in tempo reale", il polling è forse il modo più semplice. Il polling può essere utilizzato in modo efficace quando l'intervallo di polling è relativamente lungo (ovvero secondi, minuti o ore anziché istantanei) e i cicli di clock consumati controllando la connessione o la risorsa non contano davvero.


3
Questo, mille volte questo. È accettato perché di solito è abbastanza buono.
corsiKa

1
Questa è una risposta abbastanza buona
Zain R,

31

Il protocollo HTTP è limitato in quanto il client DEVE essere quello che avvia la richiesta. Il server non può comunicare con il client a meno che non risponda alla richiesta di un client.

Quindi, per adattare il tuo esempio del mondo reale, aggiungi la seguente moderazione:

  • L'utente 2 può rispondere SOLO alle domande dell'utente 1 con una risposta a frase singola, dopo la quale l'utente 1 deve partire. L'utente 2 non ha altro modo di comunicare.

Con questa nuova moderazione, come faresti se non il polling?


6
HTTP 2.0 supporterà i push del server. "Il push consente ai server di inviare rappresentazioni ai client senza una richiesta esplicita." en.wikipedia.org/wiki/HTTP_2.0
kaptan

5
@kaptan, è fantastico, ma non è disponibile. Accontentati di ciò che hai.
riwalk

7
C'è anche il polling lungo che è disponibile in questo momento e simula un modello push usando un pull.
Tim B,

24
@dennis: Avendo scritto un software di automazione industriale, vorrei solo commentare l'esempio del tuo sondaggio sui sensori. I sensori di polling hanno due scopi: il più ovvio è recuperare nuovi dati. Il meno ovvio è rilevare che il sensore è ancora in vita, non si è schiantato a causa di un bug o brucia a causa di un incendio in fabbrica o si è fuso a causa di un incidente industriale. Anche il silenzio, il fatto di non ricevere risposta, è un dato prezioso.
Slebetman,

3
@dennis I sensori spesso percepiscono molto più velocemente di quanto tu sia interessato ai dati. Il polling ti consente di ottenere il valore del sensore esattamente quando lo desideri, senza essere invaso da aggiornamenti che non ti interessano. (Immagina se il sistema operativo ha notificato la tua applicazione ogni volta che un file cambiava in un punto qualsiasi del disco, invece che l'applicazione deve aprire e leggere il file)
immibis

13

Perché il polling è accettato? Perché in realtà ogni soluzione è in realtà un polling di basso livello!

Se il server ti aggiorna non appena sono disponibili nuove immagini, di solito deve avere una connessione con te, perché gli indirizzi IP cambiano spesso e non sai mai se qualcuno non è più interessato, quindi il client deve inviare una qualche forma di segnale keep-alive, ad esempio "Sono ancora qui, non sono offline"

Tutte le connessioni con stato (ad esempio TCP / IP) funzionano allo stesso modo, poiché è possibile inviare solo pacchetti di dati singolari su Internet; non si sa mai se l'altra parte è ancora lì.

Quindi ogni protocollo ha un timeout. Se un'entità non risponde entro X secondi, si presume che sia morta. Quindi, anche se hai solo una connessione aperta tra server e client, senza inviare alcun dato, il server e il client devono inviare pacchetti keep-alive regolari (questo viene gestito a basso livello se si apre una connessione tra di loro) - e come è questo alla fine è diverso dal polling?

Quindi l'approccio migliore sarebbe probabilmente longpolling:

Il client invia una richiesta immediatamente dopo aver caricato il sito (ad esempio, dicendo al fotografo "Dimmi se ci sono nuove foto"), ma il server non risponde se non ci sono nuove foto. Non appena la richiesta scade, il client chiede di nuovo.

Se il server ora ha nuove immagini, può immediatamente rispondere a tutti i client che si mettono in fila per le nuove immagini. Quindi il tuo tempo di reazione dopo una nuova immagine è ancora più breve rispetto alla push, poiché il client sta ancora aspettando una connessione aperta per una risposta e non devi creare una connessione al client. E le richieste di polling dal client non sono molto più traffico di una costante connessione tra client e server per una risposta!


Non sono d'accordo sul fatto che ogni soluzione finisca per essere un polling di basso livello. Stai confondendo il polling richiesto per inviare i dati con il polling necessario per sapere quando un client viene perso. Sì, quest'ultimo finirà sempre per eseguire il polling da qualche parte nello stack del protocollo, ma ciò può avvenire a una frequenza molto bassa (come una volta ogni cinque minuti) mentre il polling per i dati effettivi ogni secondo è uno spreco che PUO 'essere evitato con vere notifiche push che NON sta eseguendo il polling a nessun livello dello stack.
Allon Guralnek,

I primi pacchetti keepalive vengono eseguiti a una frequenza abbastanza elevata, perché si desidera evitare intervalli di timeout comuni, quindi pochi secondi non sono inusuali per TCP / IP e quasi tutto ciò che non utilizza tcp può essere bloccato dai firewall. Quindi, quando devo inviare un pacchetto di dati ogni X secondi, perché non riempirlo con alcuni dati praticamente a costo zero?
Falco,

1
@Guralnek anche se avessi una connessione con un intervallo di mantenimento in vita di 5 minuti il ​​timeout sarebbe maggiore, poiché devi aggiungere ritardo effettivo e pacchetti persi. E il server manterrebbe molte connessioni per 5 minuti dopo che i client si sono disconnessi, quindi nel complesso questo costerebbe probabilmente più risorse del server risparmiando solo una larghezza di banda minima
Falco,

1
+1 per il polling lungo. Cerca Comet en.wikipedia.org/wiki/Comet_%28programming%29
Zan Lynx

9

Un vantaggio del polling è che limita il danno che può essere causato se un messaggio scompare o lo stato di qualcosa viene bloccato. Se X chiede a Y il suo stato una volta ogni cinque secondi, la perdita di una richiesta o di una risposta comporterà semplicemente il mancato aggiornamento delle informazioni di X di dieci secondi anziché di 5. Se Y viene riavviato, X può scoprirlo al successivo tempo Y è in grado di rispondere a uno dei messaggi di X. Se X viene riavviato, potrebbe non preoccuparsi di chiedere a Y qualcosa in seguito, ma chiunque osservi lo stato di X dovrebbe riconoscere che è stato riavviato.

Se invece di X esegua il polling di Y, X fa affidamento su Y per informarlo ogni volta che cambia il suo stato, quindi se lo stato di Y cambia e invia un messaggio a X, ma per qualsiasi motivo il messaggio non sia stato ricevuto, X potrebbe non venire mai a conoscenza del cambiamento . Allo stesso modo se Y viene riavviato e non ha mai motivo di inviare a X un messaggio su qualcosa.

In alcuni casi può essere utile per X richiedere a Y di inviare autonomamente messaggi con il suo stato, periodicamente o quando cambia, e avere il sondaggio X solo se va troppo a lungo senza sentire nulla da Y. Tale progetto può eliminare il è necessario che X invii la maggior parte dei suoi messaggi (in genere, X dovrebbe almeno occasionalmente informare Y che è ancora interessato a ricevere messaggi e Y dovrebbe interrompere l'invio di messaggi se dura troppo a lungo senza alcuna indicazione di interesse). Un tale progetto richiederebbe, tuttavia, che Y sia persistentemantenere le informazioni su X, piuttosto che essere in grado di inviare semplicemente una risposta a chiunque abbia effettuato il polling e quindi dimenticare immediatamente chi fosse. Se Y è un sistema incorporato, una tale semplificazione può aiutare a ridurre sufficientemente i requisiti di memoria per consentire l'uso di un controller più piccolo ed economico.

Il polling può avere un ulteriore vantaggio quando si utilizza un mezzo di comunicazione potenzialmente inaffidabile (ad es. UDP o radio): può in gran parte eliminare la necessità di riconoscimenti a livello di link. Se X invia a Y una richiesta di stato Q, Y risponde con un rapporto sullo stato R e X sente R, X non avrà bisogno di sentire alcun tipo di riconoscimento a livello di collegamento perché Q sappia che è stato ricevuto. Al contrario, una volta che Y invia R, non ha bisogno di sapere o preoccuparsi se X l'ha ricevuto. Se X invia una richiesta di stato e non riceve alcuna risposta, può inviarne un'altra. Se Y invia un rapporto e X non lo sente, X invierà un'altra richiesta. Se ogni richiesta viene emessa una volta e viene fornita una risposta oppure no, nessuna delle parti deve sapere o preoccuparsi se un particolare messaggio è stato ricevuto. Poiché l'invio di un riconoscimento può richiedere quasi la stessa larghezza di banda di una richiesta o di un rapporto sullo stato, l'utilizzo di un viaggio di andata e ritorno di report di richiesta non costa molto più di quanto farebbe un report e un riconoscimento non richiesti. Se X invia alcune richieste senza ottenere risposte, su alcune reti con routing dinamico potrebbe essere necessario abilitare i riconoscimenti a livello di collegamento (e chiedere nella sua richiesta che Y faccia altrettanto) in modo che lo stack di protocollo sottostante possa riconoscere il problema di consegna e cercare un nuovo percorso, ma quando le cose stanno funzionando un modello di report delle richieste sarà più efficiente rispetto all'utilizzo dei riconoscimenti a livello di link.


Il problema di cui parli con Y che spinge i messaggi su X (secondo paragrafo) può essere risolto avendo un numero seriale allegato a ciascun messaggio. Se un messaggio viene perso, X lo saprà perché non ha ricevuto quel seriale. A quel punto possono essere necessarie altre misure per la sincronizzazione con Y. DNS master -> la replica slave funziona in questo modo.
korylprince,

@korylprince: entrambe le parti possono scoprire il messaggio mancante se l'altra parte ha occasione di inviare qualcosa (e lo fa con successo) o se ha motivo di aspettarsi qualcosa dall'altra parte e non lo riceve mai. Se una parte invia un aggiornamento dello stato e non richiede riconoscimenti o si arrende dopo aver riprovato alcune volte e l'altra parte non si aspetta trasmissioni pianificate, l'altra parte non saprà che la connessione è scomparsa.
supercat

2
@korylprince - Il problema è che, senza messaggi periodici, X potrebbe rilevare il messaggio mancante con un giorno di ritardo o un anno di ritardo o 10 anni di ritardo. Per rilevare il pacchetto mancante in tempi ragionevoli è necessario in qualche modo effettuare il polling. Puoi "tirare" il sondaggio oppure puoi "spingere" il sondaggio. Il primo si chiama "polling", il secondo si chiama "battito cardiaco"
slebetman

Entrambi molto veri. Tutto dipende dalla situazione.
korylprince,

@slebetman: senza messaggi periodici, se Y viene riavviato, potrebbe non esserci alcun meccanismo attraverso il quale X lo scoprirà mai .
supercat,

1

La domanda è di bilanciare la quantità di sondaggi non necessari rispetto alla quantità di spin inutili.

Se esegui il polling:

  • Ottieni una risposta proprio in questo momento. Buono se lo chiedi solo occasionalmente o hai bisogno di un set di dati proprio in questo momento.
  • Si potrebbe ottenere una risposta "senza contenuto", causando un carico inutile sulla linea.
  • Metti il ​​carico sulla linea solo quando esegui il polling, ma sempre quando esegui il polling.

Se si preme:

  • Fornisci la risposta quando è disponibile, il che consente un'elaborazione immediata sul lato client.
  • È possibile fornire dati a client che non sono interessati a tali dati, causando un carico inutile sulla linea.
  • Metti il ​​carico sulla linea ogni volta che ci sono nuovi dati, ma solo quando ci sono nuovi dati.

Esistono diverse soluzioni su come gestire i vari scenari e i loro svantaggi, come ad esempio un tempo minimo tra i sondaggi, i proxy solo sondaggio per scaricare il carico dal sistema principale o, per i push, un regolamento da registrare e specificare i dati desiderati seguiti da annullare la registrazione al log-off. Quale si adatta meglio non è nulla che si possa dire in generale, dipende dal sistema.

Nel tuo esempio il polling non è la soluzione più efficiente, ma la più pratica. Scrivere un sistema di polling in JavaScript è molto semplice ed è anche molto semplice implementarlo sul lato della consegna. Un server creato per fornire dati di immagine dovrebbe essere in grado di gestire le richieste extra e, in caso contrario, può essere ridimensionato in modo lineare, poiché i dati sono per lo più statici e possono quindi essere facilmente memorizzati nella cache.

Un metodo push che implementa un log-in, una descrizione dei dati desiderati e, infine, un log-off sarebbe il più efficiente, ma è probabilmente troppo complesso per lo "script-kiddy" medio, e deve affrontare la domanda: cosa succede se l'utente basta chiudere il browser e non è possibile eseguire il log-off?

Forse è meglio avere più utenti (poiché l'accesso è facile) che risparmiare qualche soldo su un altro server cache?


1

Per qualche ragione, in questi giorni, tutti gli sviluppatori web più giovani sembrano aver dimenticato le lezioni del passato e perché alcune cose si sono evolute nel modo in cui hanno fatto.

  1. La larghezza di banda era un problema
  2. La connessione potrebbe essere intermittente.
  3. I browser non avevano la stessa potenza di calcolo
  4. C'erano altri metodi per accedere al contenuto. Il web non è w3.

Di fronte a questi vincoli, potresti non avere una comunicazione bidirezionale costante. E se guardassi il modello OSI, scopriresti che la maggior parte delle considerazioni sono pensate per disaccoppiare la persistenza con la connessione sottostante.

Tenendo presente ciò, un metodo di polling per estrarre informazioni è un ottimo modo per ridurre la larghezza di banda e il calcolo sul lato client. L'ascesa della spinta è in realtà solo il client che esegue costantemente polling o socket Web. Personalmente, se fossi tutti gli altri là fuori, apprezzerei la regolarità del polling come mezzo di analisi del traffico, in cui una richiesta GET / POST fuori dal tempo segnalerebbe un uomo nella situazione di mezzo di qualche tipo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.