J'ai demandé ce qui est maintenant une question supprimée par la communauté sur SO sur pourquoi quelqu'un utiliserait-il le javascript Promise.race
, et un utilisateur de haut niveau a commenté ceci:
Si vous avez deux services qui calculent une valeur, vous pouvez les interroger en parallèle et utiliser la valeur qui est renvoyée en premier, plutôt que d'en interroger un, d'attendre un échec, puis d'interroger le second.
J'ai cherché sur la redondance et ce cas d'utilisation en général, mais je n'ai rien trouvé et, à partir de mon POV, ce n'est jamais une bonne idée d'ajouter simplement une charge de travail à un serveur / service si vous n'utilisez pas la réponse.
programming-practices
Adelin
la source
la source
Réponses:
Je dirais que c'est davantage une question économique. Cependant, c'est un jugement que les ingénieurs devraient pouvoir faire. Par conséquent, je réponds.
Je divise ma réponse en quatre parties:
Gestion des risques
Ainsi, parfois, votre client ne parvient pas à obtenir une réponse du serveur. Je suppose que ce n'est pas à cause d'une erreur de programmation (sinon la solution est de le réparer, alors allez-y). Au contraire, cela doit être dû à une situation fortuite échappant à votre contrôle ...
Mais pas au-delà de vos connaissances. Tu dois savoir:
Par exemple, si l'échec et la nouvelle tentative ne se produisent que dans environ 2% des cas, cela ne vaut probablement pas la peine d'y remédier. Si cela se produit environ 80% du temps, eh bien ... ça dépend ...
Combien de temps le client doit-il attendre? Et comment cela se traduit-il en coûts ... vous voyez, vous avez un petit retard dans une application régulière, ce n'est probablement pas un gros problème. S'il est important et que vous disposez d'une application en temps réel ou d'un jeu vidéo en ligne, cela détournera les utilisateurs et vous feriez probablement mieux d'investir dans des serveurs plus nombreux ou meilleurs. Sinon, vous pouvez probablement mettre un message "chargement" ou "attente de serveur". À moins que le délai ne soit vraiment important (de l'ordre de dizaines de secondes), il peut être trop important même pour l'application régulière.
Stratégies
Comme je l'ai dit plus haut, il y a plus d'une façon de résoudre ce problème. Je suppose que vous disposez déjà de l'implémentation de la boucle try-fail-retry. Voyons donc ...
Maintenant, remarquez que je dis que ceux-ci peuvent toujours échouer. Si nous supposons qu'une requête à un serveur a 80% de chances d'échec, alors une requête parallèle à deux serveurs a 64% de chances d'échec. Par conséquent, vous devrez peut-être encore réessayer.
Un avantage supplémentaire de choisir le serveur le plus rapide et de continuer à l'utiliser, est que le serveur le plus rapide est également le moins susceptible d'échouer en raison de problèmes de réseau.
Ce qui me rappelle, si vous pouvez comprendre pourquoi la demande échoue, faites-le. Il peut vous aider à mieux gérer la situation, même si vous ne pouvez pas empêcher les échecs. Par exemple, avez-vous besoin de plus de vitesse de transfert côté serveur?
Un peu plus:
Et qui a dit que vous ne deviez en faire qu'une? Vous pouvez mettre un message de chargement, interroger plusieurs serveurs répartis sur le wrold pour choisir le plus rapide et l'utiliser uniquement à partir de là, en cas d'échec, réessayer sur une boucle, et faire en sorte que chacun de ces serveurs soit un cluster de machines avec équilibrage de charge . Pourquoi pas? Eh bien, les coûts ...
Frais
Il y a quatre coûts:
Vous devez les équilibrer.
Par exemple, disons que vous gagnez environ un dollar par utilisateur satisfait. Que vous avez 3000 utilisateurs par jour. Que les demandes échouent environ 50% du temps. Et que 2% des utilisateurs partent sans payer lorsque la demande échoue. Cela signifie que vous perdez (3000 * 50% * 2%) 30 dollars par jour. Maintenant, disons que le développement de la nouvelle fonctionnalité vous coûtera 100 dollars et le déploiement des serveurs vous coûtera 800 dollars - et en ignorant les coûts d'exécution - cela signifie que vous auriez un retour sur investissement en ((100 + 800) / 30 ) 30 jours. Maintenant, vous pouvez vérifier votre budget et décider.
Ne considérez pas ces valeurs comme représentatives de la réalité, je les ai choisies pour des raisons mathématiques.
Addendums:
Le fait est que si vous considérez le problème en termes d'équilibrage des coûts, vous pouvez faire une estimation du coût des stratégies que vous envisagez et utiliser cette analyse pour décider.
Intuition
L'intuition est favorisée par l'expérience. Je ne suggère pas de faire ce genre d'analyse à chaque fois. Certaines personnes le font, et ça va. Je vous suggère d'avoir une certaine compréhension de cela et de développer une intuition pour cela.
De plus, en ingénierie, en plus des connaissances que nous obtenons de la science réelle, nous apprenons également dans la pratique et compilons des directives sur ce qui fonctionne et ce qui ne fonctionne pas. Par conséquent, il est souvent sage de voir l'état de l'art ... bien que, parfois, vous ayez besoin de voir en dehors de votre région.
Dans ce cas, je regarderais les jeux vidéo en ligne. Ils ont des écrans de chargement, ils ont plusieurs serveurs, ils choisiront un serveur en fonction de la latence, et ils peuvent même permettre à l'utilisateur de changer de serveur. Nous savons que cela fonctionne.
Je suggérerais de le faire au lieu de gaspiller le trafic réseau et le temps du serveur à chaque demande, sachez également que même avec un serveur redondant, une panne peut se produire.
la source
Ceci est acceptable si le temps du client est plus précieux que le temps sur le serveur.
Si le client doit être rapide et précis. Vous pouvez justifier l'interrogation de plusieurs serveurs. Et il est agréable d'annuler la demande si une réponse valide est reçue.
Et bien sûr, il est toujours sage de consulter les propriétaires / gestionnaires des serveurs.
la source
Cette technique peut réduire la latence. Le temps de réponse du serveur n'est pas déterministe. À grande échelle, il est probable qu'au moins un serveur affiche des temps de réponse médiocres. Tout ce qui utilise ce serveur aura donc également des temps de réponse médiocres. En soumettant à plusieurs serveurs, on atténue le risque de parler à un serveur peu performant.
Les coûts incluent des trafics réseau supplémentaires, un traitement de serveur gaspillé et la complexité des applications (cela peut être caché dans une bibliothèque). Ces coûts peuvent être réduits en annulant les demandes inutilisées ou en attendant brièvement avant d'envoyer une deuxième demande.
Voici un papier , et un autre . Je me souviens avoir lu un article de Google sur leur mise en œuvre également.
la source
Je suis principalement d'accord avec les autres réponses, mais je pense que cela devrait être extrêmement rare dans la pratique. Je voulais partager un exemple beaucoup plus courant et raisonnable pour le moment où vous l'utiliseriez
Promise.race()
, quelque chose que j'ai utilisé il y a quelques semaines (enfin, l'équivalent de python).Supposons que vous ayez une longue liste de tâches, certaines pouvant être exécutées en parallèle et d'autres devant être exécutées avant d'autres. Vous pouvez démarrer toutes les tâches sans dépendances, puis attendre sur cette liste avec
Promise.race()
. Dès que la première tâche est terminée, vous pouvez démarrer toutes les tâches qui dépendaient de cette première tâche, et àPromise.race()
nouveau sur la nouvelle liste combinée avec les tâches inachevées de la liste d'origine. Continuez à répéter jusqu'à ce que toutes les tâches soient terminées.Remarque L'API de Javascript n'est pas idéalement conçue pour cela. C'est à peu près le strict minimum qui fonctionne, et vous devez ajouter un peu de code de colle. Cependant, mon point est que les fonctions comme
race()
sont rarement utilisées pour la redondance. Ils sont principalement là pour quand vous voulez réellement les résultats de toutes les promesses, mais ne voulez pas attendre qu'ils se terminent avant de prendre des mesures ultérieures.la source
new Promise
est appelé, et ne sont pas redémarrées quandPromise.race()
est appelé. Certaines implémentations prometteuses sont paresseuses, mais avides sont beaucoup plus courantes. Vous pouvez tester en créant une promesse dans la console qui se connecte à la console. Vous le verrez immédiatement. Ensuite, passez cette promesse àPromise.race()
. Vous verrez qu'il ne se connecte plus.En plus des considérations techniques, vous souhaiterez peut-être utiliser cette approche lorsqu'elle fait partie de votre modèle commercial réel.
Les variantes de cette approche sont relativement courantes dans les enchères en temps réel sur les annonces. Dans ce modèle, un éditeur (fournisseur d'espace publicitaire) demandera aux annonceurs (fournisseurs d'annonces) de miser sur une impression d'un utilisateur particulier. Ainsi , pour chaque telle impression, vous interroger chacun des annonceurs interrogés, l' envoi d' une requête avec les détails d'impression à un point final fourni par chaque annonceur (ou bien, un script fourni par l'annonceur en cours d' exécution en tant que point final sur vos propres serveurs), course toutes ces demandes jusqu'à un délai (par exemple 100 ms), puis en prenant l'offre la plus élevée, en ignorant les autres.
Une variante particulière de cela qui permet de réduire le temps d'attente du client consiste à demander à l'éditeur de prévoir une valeur d'objectif minimale pour l'enchère, de sorte que la première enchère d'annonceur qui dépasse cette valeur soit immédiatement acceptée (ou, si aucune des offres ne dépasse la valeur, la valeur maximale sera prise). Ainsi, dans cette variante, la première requête arrivant pourrait gagner et l'autre rejetée, même si elles sont aussi bonnes ou même meilleures.
la source