Pourquoi les sondages sont-ils acceptés dans la programmation Web?

108

Je travaille actuellement sur un projet Ruby on Rails qui affiche une liste d'images.

Un élément essentiel pour ce projet est qu’il affiche les nouvelles publications en temps réel sans qu’il soit nécessaire d’actualiser la page Web. Après avoir cherché pendant un moment, je suis tombé sur des solutions et services JavaScript tels que PubNub; cependant, aucune des solutions fournies n’avait de sens.

Dans la solution JavaScript ( interrogation ), les événements suivants se produisent:

  • L'utilisateur 1 affiche la liste des photos.
  • En arrière-plan, le code JavaScript interroge un point de terminaison toutes les secondes pour voir s'il y a une nouvelle publication.
  • L'utilisateur 2 ajoute une nouvelle photo.
  • Il y a un délai de 50 ms avant le déclenchement du nouveau cycle et l'extraction des nouvelles données.
  • Le nouveau contenu est chargé dans le DOM .

Cela semble étrange lorsque traduit à un exemple du monde réel:

  • L'utilisateur 1 tient une pile de photos sur son bureau.
  • Il se rend chez le photographe toutes les secondes et lui demande s'il en a un nouveau.
  • Le photographe fait une nouvelle photo.
  • Cette seconde où il / elle entre, elle peut prendre la photo et la mettre sur la pile.

À mon avis, la solution devrait être la suivante:

  • L'utilisateur 1 tient une pile de photos sur son bureau.
  • Le photographe prend une nouvelle photo.
  • Le photographe se dirige vers la pile et la pose avec le reste.

La solution PubNub est fondamentalement la même, mais cette fois-ci, un stagiaire se promène entre les parties pour partager les données.

Il va sans dire que les deux solutions consomment énormément d'énergie car elles sont déclenchées même lorsqu'il n'y a pas de données à charger.

Autant que je sache, il n'y a pas d'explication (logique) expliquant pourquoi ce mode de mise en œuvre est utilisé dans presque toutes les applications en temps réel.

Dennis
la source
195
Ignorer un instant que les navigateurs Web ne sont pas des serveurs pouvant recevoir des connexions entrantes ... attendez, non, n'ignorons pas cela.
GrandmasterB
17
@dennis: une connexion permanente et dynamique entre le serveur et le client éliminerait probablement le besoin d'interrogation, mais ce n'est pas ainsi que le Web a été conçu.
FrustratedWithFormsDesigner
58
Qu'en est-il des Websockets?
I.devries
25
Ou jetez un oeil à long sondage. En principe, vous interrogez, mais le serveur ne répond pas avant d'avoir de nouvelles données à vous montrer.
Matsemann
53
Il existe de nombreuses solutions et algorithmes parfaitement logiques dans l’espace informatique qui seraient complètement absurdes à faire dans l’espace physique.
Whatsisname

Réponses:

179

Pousser fonctionne bien pour 1 ou un nombre limité d'utilisateurs.

Modifiez maintenant le scénario avec un photographe et 1 000 utilisateurs souhaitant tous une copie de la photo. Le photographe devra marcher jusqu'à 1000 piles. Certains d'entre eux peuvent être dans un bureau verrouillé ou répartis sur le sol. Ou leur utilisateur en vacances, et pas intéressé par de nouvelles photos pour le moment.

Le photographe serait occupé à marcher tout le temps et ne prendrait pas de nouvelles photos.

Fondamentalement: un modèle de sondage / sondage s'adapte mieux à un grand nombre de lecteurs peu fiables ayant des exigences en temps réel lâches (si une image prend 10 secondes plus tard pour arriver sur une pile, quel est le problème).

Cela dit, un modèle de poussée est encore meilleur dans beaucoup de situations. Si vous avez besoin d'une faible latence (vous avez besoin de la nouvelle photo 5 après sa prise), ou si les mises à jour sont rares et si les demandes sont fréquentes et prévisibles (continuez à demander au photographe toutes les 10 secondes lorsqu'il génère une nouvelle photo chaque jour), il est inapproprié de tirer. Cela dépend de ce que vous essayez de faire. NASDAQ: poussez. Service météorologique: tirer. Photographe de mariage: probablement tirer. Agence photo de presse: probablement pousser.

ptyx
la source
32
J'aime beaucoup votre analogie avec 1000 utilisateurs, certains en vacances, d'autres non intéressés. +1
Riwalk
4
@EsbenSkovPedersen: la limite de socket n'est pas due à une adresse IP. Cela est dû au maximum de descripteur de fichier ouvert. Le nombre maximal de sockets ouverts est donc indépendant du nombre d'adresses IP que vous utilisez.
Slebetman
10
C’est une horrible analogie pour le dire gentiment. Pour que le push fonctionne, le client de tout utilisateur doit conserver une connexion ouverte. En fait, l'interrogation est une émulation d'une connexion. Ce n'est pas comme si certains clients interrogent, tous les clients sont avertis. De même, lorsque certains clients ouvrent une connexion pour les notifications push, tous les clients ne sont pas notifiés. C'est un très mauvais conseil qui invite à jeter des ressources par la fenêtre. Être bombardé de 10000 requêtes par seconde n’est pratiquement jamais meilleur marché ni meilleur que de maintenir 10000 prises ouvertes.
back2dos
8
@ptyx: l'intervalle 1s est celui qui est discuté ici. 10 000 requêtes par seconde correspond à 10 000 poignées de main TCP et 10 000 requêtes HTTP (chacune atteignant facilement 2 Ko), ce qui vous donne plusieurs ordres de grandeur et davantage de bruit de fond martelant votre serveur. Il existe une variété de bibliothèques testées au combat qui rendent les abonnements Push aussi simples que la mise en place d'un sondage. Il existe même des cadres tels que meteor.js qui résument complètement le problème. Faire appel à l'évolutivité sans autre explication n'est également pas un argument. Quoi qu'il en soit, j'ai exprimé mes doutes et ne souhaite pas commencer une discussion;)
back2dos
5
Je suis d'accord avec le commentaire de back2dos ci-dessus. Si le tirage est mieux mis à l’échelle que le push, Google, l’échange de piles, Facebook, les services de stock en ligne, etc. utiliseraient la technologie Pull. Mais ils ne le font pas. Fondamentalement, marteler le serveur au lieu de mettre en place une station d’écoute évolue terriblement. Les principaux services évitent les scrutins.
Travis J
106

Je suis vraiment surpris qu'une seule personne ait mentionné WebSockets . Le support est implémenté dans pratiquement tous les principaux navigateurs .

En fait, PubNub les utilise. Pour votre application, le navigateur souscrirait probablement à un socket qui diffuserait chaque fois qu'une nouvelle photo est disponible. Le socket n'enverrait pas la photo, mais juste un lien pour que le navigateur puisse la télécharger de manière asynchrone.

Dans votre exemple, imaginez quelque chose comme:

  1. L'utilisateur (s) indique au photographe qu'il souhaite connaître toutes les futures photos
  2. Le photographe dit par haut-parleur qu'une nouvelle photo est disponible
  3. L'utilisateur demande une photo au photographe

Cela ressemble un peu à votre exemple de solution d'origine. C'est plus efficace que l'interrogation, car le client n'a pas à envoyer de données au serveur (sauf peut-être des pulsations .)

En outre, comme d'autres l'ont mentionné, il existe d'autres méthodes qui sont meilleures que la simple interrogation et qui fonctionnent dans les anciens navigateurs ( longpolling, et autres ).

Korylprince
la source
43
@ RobertHarvey pourquoi les WebSockets ne sont-ils pas liés à la question? La question demande si les sondages sont une stratégie acceptable, et de nos jours, ce n'est clairement pas acceptable (ou pas du moins optimal). Les WebSockets, les événements envoyés par le serveur et les longues interrogations fonctionnent beaucoup mieux dans pratiquement tous les cas d'utilisation.
Fabrício Matté
7
@ RobertHarvey, c’était juste mon interprétation, pas de recadrage à ma connaissance. Bien sûr, la question posée est de savoir pourquoi est-ce toujours accepté et non quelle est la stratégie optimale , mais ces deux éléments sont toujours étroitement liés à l’imho.
Fabrício Matté le
25
Les WebSockets (et autres) sont ce que vous pouvez faire de plus près pour implémenter la "solution" du PO, donc je pense que c'est très pertinent bien qu'il ne l'ait pas mentionné spécifiquement.
korylprince
6
Sans parler des StackExchangesites tels que celui sur lequel vous êtes actuellement (sauf si vous regardez cette page Web mise en cache / enregistrée) WebSockets. C'est pourquoi je me demandais aussi pourquoi personne jusqu'à la mention @korylprince WebSockets.
Trysis
6
@ FabrícioMatté: en réalité, pas tous les cas d'utilisation. Une interrogation longue nécessite de garder un socket ouvert pour chaque utilisateur, qui utilise les ressources du système. En ce qui concerne les services qui ne nécessitent pas beaucoup de temps mais qui ont de nombreux utilisateurs, maintenir un socket ouvert coûte généralement plus cher que de desservir de temps en temps un court serveur 304. Pour la plupart des services, un léger retard n'est pas un problème. Une seule machine peut généralement servir plus de clients avec polling qu'avec push.
Lie Ryan
42

Parfois assez bon est assez bon.

La polling est peut-être le moyen le plus simple de mettre en œuvre un processus de communication "en temps réel". L'interrogation peut être utilisée efficacement lorsque l'intervalle d'interrogation est relativement long (secondes, minutes ou heures plutôt qu'instantané) et que les cycles d'horloge consommés en vérifiant la connexion ou la ressource importent peu.

Robert Harvey
la source
3
Ceci, mille fois cela. C'est accepté parce que c'est généralement suffisant.
CorsiKa
1
C'est une assez bonne réponse
Zain R
31

Le protocole HTTP est limité en ce que le client DOIT être le premier à lancer la demande. Le serveur ne peut pas communiquer avec le client à moins de répondre à une demande du client.

Donc, pour ajuster votre exemple du monde réel, ajoutez la contrainte suivante:

  • L'utilisateur 2 peut UNIQUEMENT répondre aux questions de l'utilisateur 1 avec une réponse en une seule phrase, après quoi l'utilisateur 1 doit partir. L'utilisateur 2 n'a pas d'autre moyen de communiquer.

Avec cette nouvelle contrainte, comment le feriez-vous autrement que par sondage?

riwalk
la source
6
HTTP 2.0 prendra en charge les transmissions serveur. "Pousser permet aux serveurs d'envoyer des représentations aux clients sans demande explicite." en.wikipedia.org/wiki/HTTP_2.0
kaptan
5
@ kaptan, c'est génial, mais ce n'est pas disponible. Faites avec ce que vous avez.
Riwalk
7
Il existe également une longue interrogation qui est disponible actuellement et simule un modèle push utilisant un pull.
Tim B
24
@dennis: Après avoir écrit un logiciel d'automatisation industrielle, je voudrais juste commenter votre exemple d'interrogation de capteurs. Les sondes à interrogation ont deux objectifs - le plus évident est d’extraire de nouvelles données. Le moins évident est de détecter que le capteur est toujours en vie, non planté en raison d'un bug ou d'une brûlure en raison d'un incendie en usine ou fondu en raison d'un accident du travail. Le silence, le fait de ne recevoir aucune réponse, est également une donnée précieuse.
Slebetman
3
@dennis Les capteurs détectent souvent beaucoup plus rapidement que les données vous intéressent. L'interrogation vous permet d'obtenir la valeur du capteur exactement quand vous le souhaitez, sans être inondée de mises à jour dont vous ne vous souciez pas. (Imaginons que le système d'exploitation avertisse votre application chaque fois qu'un fichier est modifié n'importe où sur le disque, au lieu que votre application ait besoin de l'ouvrir et de le lire.)
utilisateur253751 Le
13

Pourquoi les sondages sont-ils acceptés? Parce qu'en réalité, chaque solution est en réalité un polling de bas niveau!

Si le serveur doit vous mettre à jour dès que de nouvelles images sont disponibles, il doit généralement vous connecter, car les adresses IP changent souvent et vous ne savez jamais si une personne ne vous intéresse plus. Le client doit donc envoyer une forme de signal Keep-Alive, par exemple, "Je suis toujours là, je ne suis pas hors ligne"

Toutes les connexions avec état (par exemple, TCP / IP) fonctionnent de la même manière, car vous ne pouvez envoyer que des paquets de données uniques sur Internet. on ne sait jamais si l'autre partie est toujours là.

Donc, chaque protocole a un délai d'attente. Si une entité ne répond pas dans un délai de X secondes, elle est supposée morte. Ainsi, même si vous n'avez qu'une connexion ouverte entre serveur et client, sans envoyer de données, le serveur et le client doivent envoyer des paquets persistants (ceci est géré à bas niveau si vous ouvrez une connexion entre eux) - et comment cela à la fin différent du sondage?

Donc, la meilleure approche serait probablement longue:

Le client envoie une demande immédiatement après le chargement du site (par exemple, en indiquant au photographe "Indiquez-moi s'il y a de nouvelles images"), mais le serveur ne répond pas s'il n'y a pas de nouvelles images. Dès que la demande expire, le client demande à nouveau.

Si le serveur dispose maintenant de nouvelles images, il peut immédiatement répondre à tous les clients en attente de nouvelles images. Ainsi, votre temps de réaction après une nouvelle image est encore plus court qu'avec le push, car le client attend toujours une réponse dans une connexion ouverte et vous n'avez pas à établir de connexion avec le client. Et les demandes d'interrogation du client ne représentent pas beaucoup plus de trafic qu'une connexion constante entre le client et le serveur pour une réponse!

Falco
la source
Je ne suis pas d'accord pour dire que chaque solution finit par être un vote à bas niveau. Vous confondez interrogation requise pour envoyer des données avec interrogation requise pour savoir quand un client est perdu. Oui, ce dernier finira toujours par interroger quelque part dans la pile de protocoles, mais cela peut être à une fréquence très basse (par exemple, une fois toutes les cinq minutes), alors que l'interrogation de données réelles chaque seconde est un gaspillage qui peut être évité avec de véritables notifications push. ce n'est pas une scrutation à aucun niveau de la pile.
Allon Guralnek
La plupart des paquets keepalive fonctionnent à une fréquence assez élevée, car vous voulez éviter les intervalles de temps communs, de sorte que peu de secondes ne sont pas rares pour TCP / IP et que presque tout ce qui n’utilise pas TCP peut être bloqué par des pare-feu. Alors, quand j’ai besoin d’envoyer un paquet de données toutes les X secondes, pourquoi ne pas le remplir avec quelques données à peu de frais?
Falco
1
@Guralnek même si vous aviez une connexion avec un intervalle de maintien en vie de 5 minutes, le délai d'attente serait plus long, car vous devez ajouter le délai réel et les paquets perdus. Et le serveur conserverait de nombreuses connexions pendant 5 min après la déconnexion des clients, donc globalement, cela coûterait probablement plus de ressources de serveur tout en économisant une bande passante minimale
Falco
1
+1 pour les longues interrogations. Recherchez Comet fr.wikipedia.org/wiki/Comet_%28programming%29
Zan Lynx
9

La polling présente l’un des avantages de limiter les dommages pouvant être causés par la disparition d’un message ou par l’état de mauvais fonctionnement. Si X demande son état à Y toutes les cinq secondes, la perte d'une demande ou d'une réponse aura pour conséquence que les informations de X seront obsolètes pendant dix secondes au lieu de 5. Si Y est redémarré, X pourra le connaître dès la prochaine le temps Y est capable de répondre à l'un des messages de X. Si X est redémarré, il ne sera peut-être jamais inutile de demander quoi que ce soit par la suite à Y, mais celui qui observe le statut de X devrait reconnaître qu'il a été redémarré.

Si, au lieu de X interrogeant Y, X se fie à Y pour l'informer de tout changement d'état, alors si l'état de Y change et envoie un message à X, mais pour une raison quelconque, ce message n'a pas été reçu, X pourrait ne jamais avoir connaissance du changement. . De même, si Y est redémarré et n’a aucune raison de lui envoyer un message.

Dans certains cas, il peut être utile pour X de demander à Y d'envoyer automatiquement des messages avec son statut, que ce soit périodiquement ou lorsqu'il change, et de n'interroger X que s'il passe trop longtemps sans rien entendre de Y. Une telle conception peut éliminer nécessité pour X d'envoyer la plupart de ses messages (généralement, X devrait au moins informer occasionnellement Y qu'il est toujours intéressé par la réception de messages, et Y devrait cesser d'envoyer des messages s'il reste trop longtemps sans aucune indication d'intérêt). Cependant, une telle conception nécessiterait que Y persisteconservez des informations sur X plutôt que de pouvoir simplement envoyer une réponse à celui qui l'a interrogé, puis d'oublier immédiatement qui c'était. Si Y est un système intégré, une telle simplification peut aider à réduire suffisamment les besoins en mémoire pour permettre l’utilisation d’un contrôleur plus petit et moins cher.

L’interrogation peut présenter un avantage supplémentaire lorsqu’on utilise un support de communication potentiellement peu fiable (par exemple, UDP ou radio): elle permet d’éliminer le recours aux accusés de réception de la couche liaison. Si X envoie à Y une demande d'état Q, Y répond par un rapport d'état R et que X entend R, X n'aura pas besoin d'entendre d'accusé de réception de couche liaison pour que Q sache qu'il a été reçu. À l'inverse, une fois que Y envoie R, il n'a pas besoin de savoir si X l'a reçu. Si X envoie une demande d'état et ne reçoit aucune réponse, il peut en envoyer une autre. Si Y envoie un rapport et que X ne l'entend pas, X enverra une autre demande. Si chaque demande sort une fois et donne une réponse ou pas, aucune des parties n'a besoin de savoir ou de se soucier de savoir si un message particulier a été reçu. Étant donné que l'envoi d'un accusé de réception peut consommer presque autant de bande passante qu'une demande d'état ou un rapport, utiliser un aller-retour de requête-rapport ne coûte pas beaucoup plus cher qu'un rapport non sollicité et un accusé de réception. Si X envoie quelques requêtes sans obtenir de réponse, il peut être nécessaire sur certains réseaux routés de manière dynamique d'activer les accusés de réception de niveau liaison (et de demander à Y de faire de même) afin que la pile de protocoles sous-jacente puisse reconnaître le problème de remise et rechercher une nouvelle route, mais lorsque les choses fonctionnent, un modèle de requête-rapport sera plus efficace que d’utiliser des accusés de réception au niveau des liens.

supercat
la source
Le problème dont vous parlez lorsque Y envoie des messages à X (deuxième paragraphe) peut être résolu en attribuant un numéro de série à chaque message. Si un message est perdu, X le saura car il n’a pas reçu ce numéro de série. À ce stade, la synchronisation avec Y peut prendre d'autres mesures. Maître DNS -> la réplication esclave fonctionne de cette manière.
korylprince
@korylprince: Chaque partie peut découvrir le message manquant si l'autre partie a l'occasion d'envoyer quelque chose (et le fait avec succès), ou si elle a des raisons d'attendre quelque chose de l'autre sans jamais le recevoir. Si une partie envoie une mise à jour de statut et si elle ne nécessite pas d'acquittement ou abandonne après plusieurs tentatives, et si l'autre partie n'attend pas d'émissions programmées, l'autre partie ne saura pas que la connexion a disparu.
Supercat
2
@korylprince - Le problème est que, sans messages périodiques, X peut détecter le message manquant avec un jour de retard, un an de retard ou 10 ans de retard. Pour détecter les paquets manquants dans un délai raisonnable, vous devez procéder à une interrogation. Vous pouvez "tirer" un sondage ou vous "pousser" un sondage. Le premier s'appelle "polling", le second s'appelle "heartbeat"
slebetman
Les deux très vrai. Cela dépend complètement de la situation.
korylprince
@slebetman: Sans messages périodiques, si Y se redémarrée, il peut y avoir aucun mécanisme par lequel X ne jamais découvrir.
Supercat
1

La question est d’équilibrer le nombre de sondages inutiles par rapport aux poussées inutiles.

Si vous interrogez:

  • Vous obtenez une réponse en ce moment même. Bon si vous ne demandez que de temps en temps ou si vous avez besoin d’un ensemble de données à ce moment précis
  • Vous pourriez obtenir une réponse «pas de contenu», ce qui causerait une charge inutile sur la ligne.
  • Vous ne chargez la ligne que lorsque vous interrogez, mais toujours lorsque vous interrogez.

Si vous poussez:

  • Vous livrez la réponse dès qu'elle est disponible, ce qui permet un traitement immédiat du côté client.
  • Vous pouvez transmettre des données à des clients qui ne sont pas intéressés par ces données, ce qui entraîne une charge inutile sur la ligne.
  • Vous chargez la ligne chaque fois qu'il y a de nouvelles données, mais uniquement lorsqu'il y a de nouvelles données.

Il existe plusieurs solutions pour gérer les différents scénarios et leurs inconvénients, comme par exemple un délai minimum entre les scrutations, des mandataires de sondages uniquement pour alléger le système principal ou, pour les poussées, un règlement pour enregistrer et spécifier les données souhaitées suivies d'une désinscription à la fermeture de session. Ce qui convient le mieux n’est pas ce que vous pouvez dire en général, cela dépend du système.

Dans votre exemple, l'interrogation n'est pas la solution la plus efficace, mais la plus pratique. Il est très facile d'écrire un système de vote en JavaScript et il est très facile de l'implémenter aussi du côté de la livraison. Un serveur conçu pour fournir des données d'image doit pouvoir gérer les demandes supplémentaires. Dans le cas contraire, il peut être mis à l'échelle de manière linéaire, car les données sont généralement statiques et peuvent donc être facilement mises en cache.

Une méthode push mettant en œuvre une connexion, une description des données demandées et enfin une déconnexion serait plus efficace, mais elle est probablement trop complexe pour un "script-kiddy" moyen, et doit répondre à la question suivante: que faire si l'utilisateur ferme simplement le navigateur et la déconnexion ne peut pas être effectuée?

Peut-être vaut-il mieux avoir plus d'utilisateurs (l'accès est facile) que de faire des économies sur un autre serveur de cache?

Deux
la source
1

Pour une raison quelconque, de nos jours, tous les jeunes développeurs Web semblent avoir oublié les leçons du passé et la raison pour laquelle certaines choses ont évolué de la même manière.

  1. La bande passante était un problème
  2. La connexion peut être intermittente.
  3. Les navigateurs n'avaient pas autant de puissance de calcul
  4. Il y avait d'autres méthodes d'accès au contenu. Le Web n'est pas W3.

Face à ces contraintes, vous pourriez ne pas avoir une communication bidirectionnelle constante. Et si vous examiniez le modèle OSI, vous constateriez que la plupart des considérations visent à découpler la persistance avec la connexion sous-jacente.

Gardant cela à l'esprit, une méthode d'interrogation consistant à extraire des informations est un excellent moyen de réduire la bande passante et les calculs du côté client. La montée en puissance de la diffusion concerne essentiellement le client effectuant des interrogations constantes ou des sockets Web. Personnellement, si j’étais tout le monde, j’apprécierais la régularité des scrutins comme moyen d’analyse du trafic, où une requête GET / POST hors délai signalait un homme dans la situation moyenne.

compte d'invité
la source