87 votes

Quelle est l'efficacité peut Meteor être tout en partageant une énorme collection parmi de nombreux clients?

Imaginez le cas suivant:

  • De 1 000 clients sont connectés à un Météore page affichant le contenu de la "Somestuff" de la collection.

  • "Somestuff" est une collection de portefeuille de 1 000 articles.

  • Quelqu'un insère un nouvel élément dans le "Somestuff" collection

Ce qui va se passer:

  • Tous Meteor.Collections sur les clients seront mis à jour c'est à dire l'insertion transmis à tous (ce qui signifie une insertion message envoyé à 1000 clients)

Quel est le coût en terme de CPU pour le serveur pour déterminer le client doit être mis à jour?

Est-il exact que seule la valeur insérée sera transmis aux clients, et non l'ensemble de la liste?

Comment cela fonctionne dans la vraie vie? Existe-il des points de référence ou des expériences d'une telle ampleur disponible?

104voto

debergalis Points 7802

La réponse courte est que seules les nouvelles données soient envoyées sur le réseau. Voici comment cela fonctionne.

Il y a trois parties importantes de la Meteor serveur de gérer abonnements: la fonction publier, qui définit la logique de ce que les données de l'abonnement; le Mongo pilote, qui regarde le base de données pour les modifications; et la zone de fusion, qui regroupe l'ensemble de client abonnements actifs et les envoie sur le réseau de l' client.

Publier fonctions

Chaque fois qu'un Météore client s'abonne à une collection, le serveur exécute un fonction publier. La publication de la fonction de travail est de comprendre l'ensemble des documents que son client devrait avoir et envoyer chaque document de la propriété dans la zone de fusion. Il s'exécute une fois pour chaque nouvel abonnement client. Vous pouvez mettre n'importe quel code JavaScript que vous voulez dans la fonction publier, comme arbitrairement complexes de contrôle d'accès en utilisant this.userId. Le publier fonction envoie les données dans la zone de fusion en appelant this.added, this.changedet this.removed. Voir la plein de publier de la documentationpour plus de détails.

La plupart de publier les fonctions n'ont pas à muck autour de bas-niveau avec le added, changed et removed API. Si un publier la fonction renvoie une Mongo curseur, le Météore serveur se connecte automatiquement à la sortie de la Mongo pilote (insert, update, et removed de rappels à l'entrée de l' fusion de zone (this.added, this.changed et this.removed). Il est assez soignée que vous pouvez faire tous les contrôles d'autorisation à l'avant dans une fonction publier et ensuite, connectez directement le pilote de base de données pour la fusion de la boîte sans que l'utilisateur n' code de la route. Et quand autopublish est activée, même ce peu est caché: le serveur établit automatiquement une requête pour tous les documents dans chaque la collecte et les pousse à la fusion de la boîte.

D'autre part, vous n'êtes pas limité à la publication de requêtes de base de données. Par exemple, vous pouvez écrire une fonction publier qui lit une position GPS à partir d'un périphérique à l'intérieur d'un Meteor.setInterval, ou les sondages d'un héritage de l'API REST à partir d'un autre service web. Dans ces cas, vous auriez émettent des modifications à la fusion de la boîte en appelant le faible niveau de l' added, changed et removed DDP de l'API.

Les Mongo du pilote

Les Mongo du conducteur de l'emploi est de regarder le base de données Mongo pour les changements de en direct des requêtes. Ces requêtes s'exécutent en permanence et le retour des mises à jour comme la modification des résultats en appelant added, removed, et changed rappels.

Mongo est pas une base de données temps réel. Ainsi, le conducteur sondages. Il garde un copie en mémoire de dernier résultat de la requête pour chaque actif en direct de la requête. Sur chaque cycle d'interrogation, il compare le résultat avec la précédente enregistré résultat, le calcul du minimum de added, removed, et changed les événements qui décrivent la différence. Si plusieurs appelants registre rappels pour le même concert de la requête, le conducteur seulement les montres d'une copie de la requête, dans un appel de rappel enregistré avec le même résultat.

Chaque fois que le serveur met à jour une collection, le pilote recalcule chaque en direct de la requête sur la collection (les Futures versions de Meteor exposer une mise à l'échelle de l'API pour limiter qui vivent des requêtes de les recalculer à la mise à jour.) L' le chauffeur, les sondages chaque requête sur un 10 secondes de la minuterie pour attraper out-of-band de la base de données mises à jour contourné le serveur Meteor.

La fusion de la boîte de

Le travail de la fusion de la boîte est de combiner les résultats (added, changed et removed appels) de l'ensemble d'un client actif de publier des fonctions dans un seul de données flux de données. Il y a une fusion de zone pour chaque client connecté. Il est titulaire d'un copie complète du client minimongo cache.

Dans votre exemple, avec un seul abonnement, la fusion de la boîte est essentiellement un pass-through. Mais une application plus complexe peut avoir plusieurs les abonnements qui peuvent se chevaucher. Si deux abonnements à la fois pour la même attribut sur le même document, la fusion de la boîte de décide de la valeur priorité et n'envoie que pour le client. Nous n'avons pas exposés l'API pour le réglage de priorité de souscription encore. Pour l'instant, la priorité est déterminé par l'ordonnance, le client s'abonne à des ensembles de données. La première l'abonnement d'un client rend a la priorité la plus élevée, la deuxième l'abonnement est plus élevé suivant, et ainsi de suite.

Parce que la fusion est l'état du client, il peut envoyer le minimum la quantité de données à conserver chaque client jusqu'à ce jour, peu importe ce que publier fonction qui le nourrit.

Ce qui se passe sur une mise à jour

Alors maintenant, nous avons préparé le terrain pour votre scénario.

Nous avons de 1 000 clients connectés. Chaque abonné à la même vivre Mongo requête (Somestuff.find({})). Depuis la requête est la même pour chaque client, le conducteur est n'exécuter qu'un seul live de la requête. Il y a 1000 active de fusion de boîtes. Et de chaque client, en fonction publier enregistré une added, changed, et removed sur que live requête qui se nourrit dans l'une des boîtes de fusion. Rien d'autre n'est connecté à la fusion des boîtes.

D'abord les Mongo du pilote. Lorsque l'un des clients insère un nouveau document en Somestuff, il déclenche un recalcul. Les Mongo pilote rediffusions la requête pour tous les documents en Somestuff, compare le résultat à la résultat précédent dans la mémoire, trouve qu'il y a un nouveau document, et les appels de chacune des 1 000 inscrits insert rappels.

Ensuite, le publier fonctions. Il y a très peu de ce qui se passe ici: chaque de la de 1 000 insert rappels pousse des données dans la zone de fusion par appelant added.

Enfin, chaque fusion de la boîte de contrôles de ces nouveaux attributs à l'encontre de ses copie en mémoire de son client en cache. Dans chaque cas, il constate que la les valeurs ne sont pas encore sur le client et de ne pas l'ombre d'une valeur existante. Donc la fusion de la boîte émet un DDP DATA message sur le SockJS connexion à son client et de ses mises à jour côté serveur copie en mémoire.

Total CPU est le coût de diff un Mongo requête, plus le coût de De 1 000 fusionner les boîtes de vérification de leurs clients de l'état et la construction d'un nouveau DDP charge utile du message. Les seules données qui circulent sur le fil est un seul Objet JSON envoyé à chacune des 1 000 clients, correspondant à la nouvelle document dans la base de données, plus un message RPC sur le serveur de l' client qui fait l'insert d'origine.

Optimisations

Voici ce que nous avons certainement prévu.

  • Plus efficace Mongo pilote. Nous optimisé le pilote dans 0.5.1 ne s'exécute qu'un seul observateur par requête distinct.

  • Pas tous les DB changement devrait déclencher un recalcul d'une requête. Nous peut rendre certains automatisé des améliorations, mais la meilleure approche est une API qui permet au développeur de spécifier des requêtes besoin de relancer. Pour exemple, il est évident que pour un développeur que l'insertion d'un message dans un chat ne devrait pas invalider un live de requête pour les messages dans un deuxième chambre.

  • Les Mongo du pilote, de publier, et fusionner boîte n'avez pas besoin d'exécuter dans le même processus, ou même sur la même machine. Certaines applications complexes vivre requêtes et ont besoin de plus de CPU pour regarder la base de données. D'autres ont seulement un peu de requêtes distinctes (imaginez un moteur de blog), mais probablement beaucoup de clients connectés -- ces besoin de plus de CPU pour la fusion les boîtes. La séparation de ces éléments nous laisser échelle de chaque pièce de façon indépendante.

  • De nombreuses bases de données de soutenir les déclencheurs d'incendie lorsqu'une ligne est mise à jour et fournir les anciennes et les nouvelles lignes. Avec cette fonctionnalité, un pilote de base de données pourrait enregistrer un déclencheur au lieu de l'interrogation des modifications.

27voto

Andrew Mao Points 10616

De mon expérience, à l'aide de nombreux clients tout en partageant une énorme collection dans le Météore est essentiellement réaliste, à partir de la version 0.7.0.1. Je vais essayer d'expliquer pourquoi.

Comme décrit dans le post ci-dessus et aussi dans https://github.com/meteor/meteor/issues/1821le météore serveur doit conserver une copie des données publiées pour chaque client dans la zone de fusion. C'est ce qui permet le Météore de la magie, mais aussi des résultats dans toutes les grandes bases de données partagées à être à plusieurs reprises conservé dans la mémoire du nœud de processus. Même lors de l'utilisation d'une possible optimisation statique des collections comme dans (Est-il un moyen de dire meteor une collection est statique (ne changera jamais)?), nous avons connu un énorme problème avec la CPU et de la Mémoire du Nœud de processus.

Dans notre cas, nous avons été la publication d'une collection de 15k documents à chaque client qui a été complètement statique. Le problème est que la copie de ces documents à un client de fusion de zone (en mémoire) lors de la connexion essentiellement porté le Nœud de processus à 100% de CPU pendant près d'une seconde, et a abouti à une grande utilisation supplémentaire de la mémoire. C'est intrinsèquement infranchissables, parce que tout client qui se connecte mettre le serveur à genoux (et connexions simultanées va se bloquer les uns les autres) et l'utilisation de la mémoire vont augmenter de façon linéaire dans le nombre de clients. Dans notre cas, chaque client a fait qu' ~60MO de l'utilisation de la mémoire, même si les premières données transférées n'était que d'environ 5 MO.

Dans notre cas, parce que la collection était statique, nous avons résolu ce problème par l'envoi de tous les documents .json le fichier, qui a été gzippé par nginx, et de les charger dans un recueil anonyme, ce qui entraîne une ~1 MO de transfert de données avec aucune autre PROCESSEUR ou de la mémoire dans le nœud de processus et un chargement beaucoup plus rapide de temps. Toutes les opérations au cours de cette collection ont été fait en utilisant _ids de beaucoup de petites publications sur le serveur, permettant de conserver la plupart des avantages d'un Météore. Cela a permis à l'application à l'échelle beaucoup plus de clients. En outre, parce que notre application est principalement en lecture seule, nous avons continué d'améliorer l'évolutivité par l'exécution de plusieurs Meteor instances derrière nginx avec équilibrage de la charge (mais avec un seul Mongo), chaque Nœud de l'instance est seul thread.

Cependant, la question du partage de gros, inscriptible collections parmi de multiples clients est un problème d'ingénierie qui doit être résolu par un Météore. Il y a probablement une meilleure solution que de garder une copie de tout pour chaque client, mais qui nécessite beaucoup de réflexion en tant que systèmes distribués problème. Les enjeux actuels du massif de la CPU et de la mémoire ne sont pas à l'échelle.

4voto

javajosh Points 162

L'expérience que vous pouvez utiliser pour répondre à cette question:

  1. Installer un test météore: meteor create --example todos
  2. Exécuter sous Webkit inspecteur (WKI).
  3. Examinez le contenu de la XHR messages se déplaçant à travers le fil.
  4. Observer que l'ensemble de la collection n'est pas déplacé à travers le fil.

Pour des conseils sur la façon d'utiliser WKI consultez cet article. C'est un peu démodé, mais surtout toujours valable, surtout pour cette question.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by: