La réponse courte est que seules les nouvelles données sont envoyées sur le fil. Voici comment ça fonctionne.
Trois parties importantes du serveur Meteor gèrent les abonnements: la fonction de publication , qui définit la logique des données fournies par l'abonnement; le pilote Mongo , qui surveille la base de données pour les changements; et la boîte de fusion , qui combine tous les abonnements actifs d'un client et les envoie sur le réseau au client.
Publier des fonctions
Chaque fois qu'un client Meteor s'abonne à une collection, le serveur exécute une
fonction de publication . Le travail de la fonction de publication est de déterminer l'ensemble de documents que son client doit avoir et d'envoyer chaque propriété de document dans la zone de fusion. Il s'exécute une fois pour chaque nouveau client abonné. Vous pouvez mettre n'importe quel JavaScript de votre choix dans la fonction de publication, comme un contrôle d'accès arbitrairement complexe à l'aide de this.userId
. La fonction de publication envoie des données dans la zone de fusion en appelant this.added
, this.changed
et
this.removed
. Consultez la
documentation de publication complète pour plus de détails.
La plupart des fonctions publication ne sont pas muck autour avec le bas niveau
added
, changed
et l' removed
API, cependant. Si une fonction retourne publier un curseur mongo, le serveur Meteor se connecte automatiquement la sortie du pilote Mongo ( insert
, update
et removed
callbacks) à l'entrée de la zone de fusion ( this.added
, this.changed
et this.removed
). Il est assez intéressant de pouvoir effectuer toutes les vérifications d'autorisation à l'avance dans une fonction de publication, puis de connecter directement le pilote de base de données à la boîte de fusion sans aucun code utilisateur. Et lorsque la publication automatique est activée, même ce petit élément est masqué: le serveur configure automatiquement une requête pour tous les documents de chaque collection et les pousse dans la zone de fusion.
En revanche, vous n'êtes pas limité à la publication de requêtes de base de données. Par exemple, vous pouvez écrire une fonction de publication qui lit une position GPS à partir d'un appareil à l'intérieur d'un Meteor.setInterval
ou interroge une API REST héritée à partir d'un autre service Web. Dans ces cas, vous auriez émettez des modifications à la boîte de fusion en appelant le bas niveau added
, changed
et removed
API DDP.
Le chauffeur Mongo
Le travail du pilote Mongo est de surveiller la base de données Mongo pour les modifications apportées aux requêtes en direct. Ces requêtes fonctionnent en continu et de retour mises à jour que les résultats changent en appelant added
, removed
et changed
callbacks.
Mongo n'est pas une base de données en temps réel. Alors le chauffeur fait un sondage. Il conserve une copie en mémoire du dernier résultat de la requête pour chaque requête active active. A chaque cycle de vote, il compare le nouveau résultat avec le résultat enregistré précédent, le calcul du jeu minimum de added
, removed
et les changed
événements qui décrivent la différence. Si plusieurs appelants enregistrent des rappels pour la même requête en direct, le pilote ne regarde qu'une copie de la requête, appelant chaque rappel enregistré avec le même résultat.
Chaque fois que le serveur met à jour une collection, le pilote recalcule chaque requête en direct sur cette collection (les versions futures de Meteor exposeront une API de mise à l'échelle pour limiter les requêtes en direct recalculées lors de la mise à jour.) Le pilote interroge également chaque requête en direct sur un minuteur de 10 secondes pour attraper les mises à jour de base de données hors bande qui ont contourné le serveur Meteor.
La boîte de fusion
Le travail de la boîte de fusion est de combiner les résultats ( added
, changed
et removed
appels) de toutes publier les fonctions actives d'un client en un seul flux de données. Il existe une boîte de fusion pour chaque client connecté. Il contient une copie complète du cache minimongo du client.
Dans votre exemple avec un seul abonnement, la zone de fusion est essentiellement un pass-through. Mais une application plus complexe peut avoir plusieurs abonnements qui peuvent se chevaucher. Si deux abonnements définissent tous deux le même attribut sur le même document, la zone de fusion décide quelle valeur est prioritaire et ne l'envoie qu'au client. Nous n'avons pas encore exposé l'API pour définir la priorité d'abonnement. Pour l'instant, la priorité est déterminée par l'ordre dans lequel le client souscrit aux ensembles de données. Le premier abonnement effectué par un client a la priorité la plus élevée, le deuxième abonnement est le suivant, et ainsi de suite.
Étant donné que la zone de fusion contient l'état du client, elle peut envoyer la quantité minimale de données pour maintenir chaque client à jour, quelle que soit la fonction de publication qui le nourrit.
Que se passe-t-il lors d'une mise à jour
Alors maintenant, nous avons préparé le terrain pour votre scénario.
Nous avons 1 000 clients connectés. Chacun est abonné à la même requête Mongo en direct ( Somestuff.find({})
). La requête étant la même pour chaque client, le pilote n'exécute qu'une seule requête en direct. Il y a 1 000 boîtes de fusion actives. Et chacun de clients publient la fonction a enregistré une added
, changed
et
removed
sur cette requête en direct qui alimente l' une des boîtes de fusion. Rien d'autre n'est connecté aux boîtes de fusion.
D'abord le pilote Mongo. Lorsqu'un des clients insère un nouveau document dans Somestuff
, il déclenche un recalcul. Le pilote Mongo réexécute la requête pour tous les documents dans Somestuff
, compare le résultat au résultat précédent en mémoire, trouve qu'il y a un nouveau document et appelle chacun des 1000 insert
rappels enregistrés .
Ensuite, les fonctions de publication. Il se passe très peu de choses ici: chacun des 1000 insert
rappels pousse les données dans la zone de fusion en appelant added
.
Enfin, chaque boîte de fusion vérifie ces nouveaux attributs par rapport à sa copie en mémoire du cache de son client. Dans chaque cas, il constate que les valeurs ne sont pas encore sur le client et n'observent pas une valeur existante. Ainsi, la boîte de fusion émet un DATA
message DDP sur la connexion SockJS à son client et met à jour sa copie en mémoire côté serveur.
Le coût total du processeur correspond au coût de diffraction d'une requête Mongo, plus le coût de 1000 boîtes de fusion vérifiant l'état de leurs clients et construisant une nouvelle charge utile de message DDP. Les seules données qui circulent sur le câble sont un seul objet JSON envoyé à chacun des 1000 clients, correspondant au nouveau document de la base de données, plus un message RPC au serveur du client qui a effectué l'insertion d'origine.
Optimisations
Voici ce que nous avons définitivement prévu.
Pilote Mongo plus efficace. Nous avons
optimisé le pilote
dans 0.5.1 pour n'exécuter qu'un seul observateur par requête distincte.
Toutes les modifications de base de données ne doivent pas déclencher un recalcul d'une requête. Nous pouvons apporter des améliorations automatisées, mais la meilleure approche est une API qui permet au développeur de spécifier les requêtes à réexécuter. Par exemple, il est évident pour un développeur que l'insertion d'un message dans un salon de discussion ne doit pas invalider une requête en direct pour les messages d'une seconde salle.
Le pilote Mongo, la fonction de publication et la zone de fusion n'ont pas besoin de s'exécuter dans le même processus, ni même sur la même machine. Certaines applications exécutent des requêtes en direct complexes et nécessitent plus de processeur pour surveiller la base de données. D'autres n'ont que quelques requêtes distinctes (imaginez un moteur de blog), mais peut-être de nombreux clients connectés - ceux-ci ont besoin de plus de CPU pour les boîtes de fusion. Séparer ces composants nous permettra de mettre à l'échelle chaque pièce indépendamment.
De nombreuses bases de données prennent en charge les déclencheurs qui se déclenchent lorsqu'une ligne est mise à jour et fournissent les anciennes et les nouvelles lignes. Avec cette fonctionnalité, un pilote de base de données pourrait enregistrer un déclencheur au lieu d'interroger les modifications.