Ответ 1
Короткий ответ заключается в том, что по проводам отправляются только новые данные. Вот как это работает.
Существуют три важные части сервера Meteor, которые управляют subscriptions: функция публикации, которая определяет логику для чего данные, предоставляемые подпиской; монгольский водитель, который следит за база данных для изменений; и блок слияния, который объединяет все клиентские активные подписки и отправляет их по сети на клиент.
Опубликовать функции
Каждый раз, когда клиент Meteor подписывается на коллекцию, сервер запускает
публиковать функцию. Задача функции публикации заключается в определении набора
документов, которые его клиент должен иметь и отправлять каждое свойство документа
в поле слияния. Он запускается один раз для каждого нового клиента-подписчика. Вы
может поместить любой JavaScript, который вы хотите в функцию публикации, например
произвольно сложное управление доступом с помощью this.userId
. Публикация
функция отправляет данные в поле слияния, вызывая this.added
, this.changed
и
this.removed
. См.
полная публикация документации для
более подробная информация.
Большинство функций публикации не нужно гадать с помощью низкоуровневого
added
, changed
и removed
API. Если функция публикации возвращает Mongo
курсор, Meteor-сервер автоматически соединяет выходные данные Mongo
драйвер (insert
, update
и removed
обратные вызовы)) на вход
(this.added
, this.changed
и this.removed
). Это довольно аккуратно
что вы можете выполнить все проверки прав доступа в функции публикации и
затем напрямую подключите драйвер базы данных к ящику слияния без какого-либо пользователя
код в пути. И когда автообновление включено, даже этот маленький бит
hidden: сервер автоматически настраивает запрос для всех документов в каждом
собирать и выталкивать их в поле слияния.
С другой стороны, вы не ограничены публикацией запросов к базе данных.
Например, вы можете написать функцию публикации, которая считывает позицию GPS
от устройства внутри Meteor.setInterval
или опроса устаревшего API REST
с другой веб-службы. В этих случаях вы должны испускать изменения в
слияние, вызывая низкоуровневые added
, changed
и removed
DDP API.
Драйвер Mongo
Задача гонщика Mongo - следить за базами данных Mongo за изменениями
живые запросы. Эти запросы выполняются непрерывно и возвращают обновления в виде
изменение результатов путем вызова added
, removed
и changed
обратных вызовов.
Mongo - это не база данных в реальном времени. Так опрос водителей. Он держит
в-копии последнего результата запроса для каждого активного запроса в реальном времени. На
каждый цикл опроса, он сравнивает новый результат с предыдущим сохраненным
результат, вычисляя минимальный набор added
, removed
и changed
события, которые описывают разницу. Если зарегистрировано несколько абонентов
обратные вызовы для одного и того же прямого запроса, драйвер просматривает только одну копию
запрос, вызывающий каждый зарегистрированный обратный вызов с тем же результатом.
Каждый раз, когда сервер обновляет коллекцию, драйвер пересчитывает каждый живой запрос в этой коллекции (будущие версии Meteor будут API масштабирования для ограничения того, какие живые запросы пересчитываются при обновлении.) драйвер также проверяет каждый живой запрос на 10-секундный таймер, чтобы поймать внеполосные обновления базы данных, минуя сервер Meteor.
Блок слияния
Задача поля слияния состоит в объединении результатов (added
, changed
и removed
звонки) всех активных функций публикации клиента в единые данные
поток. Для каждого подключенного клиента есть один блок слияния. Он содержит
полная копия клиентского кэша minimongo.
В вашем примере с помощью только одной подписки поле слияния по существу, сквозной. Но более сложное приложение может иметь несколько которые могут перекрываться. Если две подписки устанавливают тот же атрибут в том же документе, поле слияния решает, какое значение имеет приоритет и только отправляет это клиенту. Мы не выставили API для настройки приоритета подписки. На данный момент приоритетом является определяется заказом, который клиент подписывает наборы данных. Первый подписка на клиента имеет наивысший приоритет, второй подписка является следующей самой высокой и т.д.
Поскольку поле слияния содержит состояние клиента, оно может отправлять минимальное количество данных, чтобы каждый клиент обновлялся, независимо от того, что публикует функция передает его.
Что происходит при обновлении
Итак, теперь мы создали сцену для вашего сценария.
У нас есть 1000 подключенных клиентов. Каждый из них подписывается на одну и ту же живую
Mongo query (Somestuff.find({})
). Поскольку запрос для каждого клиента одинаковый, драйвер
работает только один живой запрос. Имеется 1000 активных полей слияния. А также
каждая функция публикации клиента зарегистрировала added
, changed
и
removed
в этом живом запросе, который подается в один из полей слияния.
Ничего другого не связано с полями слияния.
Сначала монгонский водитель. Когда один из клиентов вставляет новый документ
в Somestuff
, он вызывает перерасчет. Монгольский водитель повторяет
запрос для всех документов в Somestuff
, сравнивает результат с
предыдущий результат в памяти, находит, что есть один новый документ, и
вызывает каждый из 1000 зарегистрированных обратных вызовов insert
.
Далее, функции публикации. Здесь мало что происходит: каждый
из 1000 обратных вызовов insert
толкает данные в поле слияния посредством
вызывая added
.
Наконец, каждый блок слияния проверяет эти новые атрибуты на
в-копии его клиентского кеша. В каждом случае он обнаруживает, что
значения еще не на клиенте и не теневое существующее значение. Так
поле слияния выдает сообщение DDP DATA
на SockJS-соединение с его
клиент и обновляет свою копию на стороне сервера в памяти.
Общая стоимость ЦП - это стоимость разграничения одного запроса Mongo, плюс стоимость 1000 слияний, проверяющих состояние своих клиентов и создание нового DDP. Единственными данными, которые протекают по проводу, являются одиночные данные Объект JSON, отправленный каждому из 1000 клиентов, соответствующий новому документ в базе данных, а также одно сообщение RPC для сервера из клиент, который сделал оригинальную вставку.
Оптимизация
Здесь мы определенно планировали.
-
Более эффективный драйвер Mongo. Мы оптимизирован драйвер в 0.5.1 для запуска только одного наблюдателя на отдельный запрос.
-
Не каждое изменение БД должно приводить к перерасчету запроса. Мы может сделать некоторые автоматизированные улучшения, но лучшим подходом является API что позволяет разработчику указать, какие запросы необходимо выполнить повторно. Для Например, разработчику очевидно, что вставка сообщения в одна чат-комната не должна аннулировать живой запрос для сообщений в вторая комната.
-
Драйвер Mongo, функция публикации и слияние не нужно запускать в том же процессе или даже на одной машине. Некоторые приложения запускать сложные живые запросы и нуждаться в большем количестве CPU для просмотра базы данных. У других есть только несколько отдельных запросов (представьте себе движок блога), но возможно, много подключенных клиентов - для этого требуется больше CPU для слияния коробки. Разделение этих компонентов позволит нам масштабировать каждую часть независимо друг от друга.
-
Многие базы данных поддерживают триггеры, которые срабатывают при обновлении строки и предоставить старые и новые строки. С этой функцией драйвер базы данных может регистрировать триггер вместо опроса для изменений.