Коротка відповідь полягає в тому, що лише нові дані надсилаються вниз. Ось як це працює.
Існує три важливі частини сервера Meteor, які керують підписками: функція публікації , яка визначає логіку, які дані надає підписка; водій Монго , який стежить за базою даних для змін; і поле злиття , яке поєднує всі активні підписки клієнта і надсилає їх по мережі клієнту.
Опублікувати функції
Щоразу, коли клієнт Meteor підписується на колекцію, сервер виконує функцію
публікації . Завдання функції публікації полягає в тому, щоб визначити набір документів, які повинен мати його клієнт, і відправити кожне властивість документа у поле злиття. Він працює один раз для кожного нового клієнта, який підписався. Ви можете помістити будь-який JavaScript у функцію публікації, наприклад, довільно складний контроль доступу this.userId
. Опублікувати функція відправляє дані в поле злиття по телефону this.added
, this.changed
і
this.removed
. Докладнішу інформацію див. У
повній документації щодо публікації .
Більшість публікувати функції не тинятися навколо з низьким рівнем
added
, changed
і removed
API, хоча. Якщо опублікувати функція повертає Монго курсора, сервер Метеор автоматично підключає вихід драйвера Монго ( insert
, update
і removed
зворотні виклики) на вхід коробки злиття ( this.added
, this.changed
і this.removed
). Досить акуратно, що ви можете виконати всі перевірки дозволу наперед у функції опублікування, а потім безпосередньо підключити драйвер бази даних до вікна злиття без жодного коду користувача. А коли ввімкнено автоматичну публікацію, навіть ця маленька частина прихована: сервер автоматично встановлює запит для всіх документів у кожній колекції та заносить їх у поле злиття.
З іншого боку, ви не обмежуєтесь публікацією запитів до бази даних. Наприклад, ви можете написати функцію публікації, яка зчитує GPS-позицію з пристрою всередині Meteor.setInterval
або опитує застарілий API REST з іншої веб-служби. У тих випадках, ви що випускаються зміни в поле злиття, викликавши низький рівень added
, changed
і removed
DDP API.
Водій Монго
Завдання водія Монго - спостерігати за базою даних Mongo за змінами на запити в реальному часі. Ці запити виконуються постійно та повертають оновлення, оскільки результати змінюються за допомогою дзвінків added
, зворотних дзвінків removed
та changed
зворотних дзвінків
Монго - це не база даних у режимі реального часу. Тож водій опитується. Він зберігає в пам'яті копію останнього результату запиту для кожного активного живого запиту. На кожному циклі опитування, він порівнює новий результат з попереднім збереженим результатом, обчисленням мінімального набору added
, removed
і changed
подій , які описують різницю. Якщо декілька абонентів реєструють зворотні дзвінки для одного і того ж запиту в реальному часі, драйвер дивиться лише одну копію запиту, викликаючи кожен зареєстрований зворотний дзвінок з тим самим результатом.
Кожен раз, коли сервер оновлює колекцію, драйвер перераховує кожен запит на реалізацію цієї колекції (майбутні версії Meteor піддають API масштабування для обмеження того, який перелік переходів в реальному часі буде оновлений. ловити оновлення позабазової бази даних, які обійшли сервер Meteor.
Коробка злиття
Робота в поле злиття є об'єднання результатів ( added
, changed
і removed
дзвінки) всіх активних публікують функцій організму клієнта в єдиний потік даних. Для кожного підключеного клієнта є одне поле злиття. У ньому зберігається повна копія мінімального кешу клієнта.
У вашому прикладі лише з однією підпискою поле злиття по суті є прохідним. Але більш складний додаток може мати кілька підписок, які можуть перекриватися. Якщо обидві підписки встановлюють один і той же атрибут на один і той же документ, поле злиття визначає, яке значення має пріоритет, і надсилає його лише клієнту. Ми ще не відкрили API для встановлення пріоритету передплати. Наразі пріоритет визначається порядком, яким клієнт підписується на набори даних. Перша підписка, яку робить клієнт, має найвищий пріоритет, друга підписка - наступна найвища і так далі.
Оскільки вікно злиття містить стан клієнта, він може надсилати мінімальну кількість даних для постійного оновлення кожного клієнта, незалежно від того, яка функція публікації подає його.
Що відбувається під час оновлення
Тож тепер ми встановили основу для вашого сценарію.
У нас є 1000 підключених клієнтів. Кожен підписаний на один і той же живий запит Mongo ( Somestuff.find({})
). Оскільки запит однаковий для кожного клієнта, драйвер виконує лише один живий запит. Є 1000 активних коробок злиття. І кожна функція публікації клієнта зареєструвала запит на added
, changed
а також
removed
у цьому запиті, який живиться в одному з полів злиття. Ніщо інше не пов'язане з полями злиття.
Спочатку водій Монго. Коли один із клієнтів вставляє новий документ у Somestuff
нього, він запускає перерахунок. Драйвер Mongo повторно виконує запит на всі документи в Somestuff
, порівнює результат із попереднім результатом у пам'яті, виявляє, що є один новий документ, і викликає кожен з 1000 зареєстрованих insert
зворотних зворотних дзвінків .
Далі, функції публікації. Тут відбувається дуже мало: кожен з 1000 insert
зворотних викликів передає дані у поле злиття, зателефонувавши added
.
Нарешті, кожне поле злиття перевіряє ці нові атрибути на копії кеш-пам'яті свого клієнта в пам'яті. У кожному конкретному випадку він виявляє, що значення ще не є клієнтом і не затьмарюють існуюче значення. Таким чином, поле злиття DATA
посилає DDP- повідомлення на підключенні SockJS до свого клієнта та оновлює його копію пам'яті на стороні сервера.
Загальна вартість процесора - це вартість, яка відрізняється одним запитом Mongo, плюс вартість 1000 скриньок злиття, що перевіряють стан своїх клієнтів та створюють нову корисну навантаження повідомлення DDP. Єдині дані, що протікають по дроту, - це один об'єкт JSON, що надсилається кожному з 1000 клієнтів, що відповідає новому документу в базі даних, плюс одне повідомлення RPC на сервер від клієнта, який зробив оригінальну вставку.
Оптимізація
Ось що ми напевно запланували.
Більш ефективний водій Монго. Ми
оптимізували драйвер
у 0.5.1 для запуску лише одного спостерігача за окремим запитом.
Не кожна зміна БД повинна викликати перерахунок запиту. Ми можемо внести деякі автоматизовані вдосконалення, але найкращим підходом є API, який дозволяє розробнику вказувати, які запити потрібно повторити. Наприклад, розробнику очевидно, що вставлення повідомлення в одну кімнату чату не повинно визнати недійсним запит на реалізацію повідомлень у другій кімнаті.
Драйвер Mongo, функція публікації та поле злиття не потрібно запускати в одному процесі або навіть на одній машині. Деякі програми виконують складні запити в реальному часі і для перегляду бази даних потрібно більше процесора. Інші мають лише кілька чітких запитів (уявіть собі блог-движок), але, можливо, багато підключених клієнтів - їм потрібно більше процесора для злиття вікон. Відокремлення цих компонентів дозволить нам масштабувати кожен фрагмент самостійно.
Багато баз даних підтримують тригери, які спрацьовують, коли рядок оновлюється та надає старі та нові рядки. За допомогою цієї функції драйвер бази даних може зареєструвати тригер замість опитування змін.