Понимание запросов в реальном времени в любом масштабе

Ознакомьтесь с этим документом, чтобы получить рекомендации по масштабированию вашего бессерверного приложения, способного выполнять тысячи операций в секунду или сотни тысяч одновременных пользователей. В документе рассматриваются сложные темы, которые помогут вам глубже понять систему. Если вы только начинаете работать с Cloud Firestore , обратитесь к краткому руководству .

Cloud Firestore и мобильные/веб-SDK Firebase предоставляют мощную модель для разработки бессерверных приложений, в которых клиентский код напрямую обращается к базе данных. SDK позволяют клиентам отслеживать обновления данных в режиме реального времени. Вы можете использовать обновления в режиме реального времени для создания адаптивных приложений, не требующих серверной инфраструктуры. Хотя настроить и запустить что-либо очень просто, важно понимать ограничения систем, составляющих Cloud Firestore , чтобы ваше бессерверное приложение масштабировалось и работало эффективно при увеличении трафика.

Советы по масштабированию вашего приложения см. в следующих разделах.

Выберите расположение базы данных, наиболее близкое к вашим пользователям

На следующей диаграмме показана архитектура приложения реального времени:

Пример архитектуры приложения реального времени

Когда приложение, работающее на устройстве пользователя (мобильном или веб-устройстве), устанавливает соединение с Cloud Firestore , оно перенаправляется на фронтенд-сервер Cloud Firestore в том же регионе , где расположена ваша база данных. Например, если ваша база данных находится в регионе us-east1 , соединение также перенаправляется на фронтенд-сервер Cloud Firestore также расположенный в регионе us-east1 . Эти соединения являются долгосрочными и остаются открытыми до тех пор, пока приложение явно не закроет их. Фронтенд считывает данные из базовых систем хранения Cloud Firestore .

Расстояние между физическим местоположением пользователя и базой данных Cloud Firestore влияет на задержку, с которой сталкивается пользователь. Например, пользователь в Индии, чьё приложение взаимодействует с базой данных в регионе Google Cloud в Северной Америке, может столкнуться с более медленной работой и менее быстрым откликом приложения, чем если бы база данных находилась ближе, например, в Индии или другой части Азии.

Надежный дизайн

Следующие темы улучшают или влияют на надежность вашего приложения:

Включить автономный режим

Пакеты Firebase SDK обеспечивают сохранение данных в автономном режиме. Если приложение на устройстве пользователя не может подключиться к Cloud Firestore , оно продолжает работать, используя локально кэшированные данные. Это обеспечивает доступ к данным даже при нестабильном интернет-соединении или полной потере доступа на несколько часов или дней. Подробнее об автономном режиме см. в разделе «Включение данных в автономном режиме» .

Понимание автоматических повторных попыток

Пакеты Firebase SDK обеспечивают повторные попытки выполнения операций и восстановление разорванных соединений. Это помогает обойти временные ошибки, вызванные перезапуском серверов или сетевыми проблемами между клиентом и базой данных.

Выбирайте между региональным и мультирегиональным расположением

При выборе между региональным и мультирегиональным размещением существует ряд компромиссов. Основное различие заключается в способе репликации данных. Это определяет гарантии доступности вашего приложения. Мультирегиональное размещение обеспечивает более высокую надежность обслуживания и повышает сохранность данных, но компромисс заключается в стоимости.

Понимание системы запросов в реальном времени

Запросы в режиме реального времени, также называемые прослушивателями снимков, позволяют приложению отслеживать изменения в базе данных и получать уведомления с малой задержкой сразу же после их изменения. Приложение может получить тот же результат, периодически опрашивая базу данных на наличие обновлений, но это часто медленнее, дороже и требует больше кода. Примеры настройки и использования запросов в режиме реального времени см. в разделе Получение обновлений в режиме реального времени . В следующих разделах подробно рассматривается работа прослушивателей снимков и описываются некоторые рекомендации по масштабированию запросов в режиме реального времени с сохранением производительности.

Представьте себе двух пользователей, которые подключаются к Cloud Firestore через приложение для обмена сообщениями, созданное с помощью одного из мобильных SDK.

Клиент А пишет в базу данных, чтобы добавлять и обновлять документы в коллекции, называемой chatroom :

collection chatroom:
    document message1:
      from: 'Sparky'
      message: 'Welcome to Cloud Firestore!'

    document message2:
      from: 'Santa'
      message: 'Presents are coming'

Клиент B прослушивает обновления в той же коллекции, используя прослушиватель снимков. Клиент B получает немедленное уведомление о каждом создании нового сообщения. На следующей диаграмме показана архитектура, лежащая в основе прослушивателя снимков:

Архитектура соединения прослушивателя снимков

Следующая последовательность событий происходит, когда Клиент B подключает прослушиватель снимков к базе данных:

  1. Клиент B открывает подключение к Cloud Firestore и регистрирует прослушиватель, вызывая onSnapshot(collection("chatroom")) через Firebase SDK. Этот прослушиватель может оставаться активным часами.
  2. Интерфейс Cloud Firestore обращается к базовой системе хранения данных для загрузки набора данных. Он загружает весь результирующий набор соответствующих документов. Мы называем это опросным запросом . Затем система проверяет правила безопасности Firebase базы данных, чтобы убедиться, что пользователь имеет доступ к этим данным. Если пользователь авторизован, база данных возвращает данные пользователю.
  3. Затем запрос клиента B переходит в режим прослушивания . Прослушиватель регистрируется в обработчике подписок и ожидает обновления данных.
  4. Клиент А теперь отправляет операцию записи для изменения документа.
  5. База данных фиксирует изменение документа в своей системе хранения.
  6. На транзакционном уровне система фиксирует одно и то же обновление во внутреннем журнале изменений. Журнал изменений устанавливает строгий порядок внесения изменений.
  7. Журнал изменений, в свою очередь, распространяет обновленные данные среди пула обработчиков подписок.
  8. Обратный сопоставитель запросов проверяет, соответствует ли обновлённый документ каким-либо зарегистрированным прослушивателям снимков. В этом примере документ соответствует прослушивателю снимков Клиента B. Как следует из названия, обратный сопоставитель запросов можно рассматривать как обычный запрос к базе данных, но в обратном порядке. Вместо поиска документов, соответствующих запросу, он эффективно ищет в запросах те, которые соответствуют входящему документу. При обнаружении совпадения система пересылает соответствующий документ прослушивателям снимков. Затем система проверяет правила безопасности Firebase базы данных, чтобы гарантировать, что данные будут доступны только авторизованным пользователям.
  9. Система пересылает обновление документа в SDK на устройстве клиента B, и срабатывает обратный вызов onSnapshot . Если включено локальное сохранение, SDK также применяет обновление к локальному кэшу.

Масштабируемость Cloud Firestore в значительной степени зависит от разветвления данных от журнала изменений к обработчикам подписок и фронтенд-серверам. Разветвление данных позволяет эффективно распространять одно изменение данных, обслуживая миллионы запросов в режиме реального времени и подключенных пользователей. Запуская множество реплик всех этих компонентов в нескольких зонах (или нескольких регионах в случае многорегионального развертывания), Cloud Firestore обеспечивает высокую доступность и масштабируемость.

Стоит отметить, что все операции чтения, инициированные мобильными и веб-SDK, следуют описанной выше модели. Они выполняют опросный запрос, а затем переходят в режим прослушивания для обеспечения согласованности. Это также относится к прослушивателям в реальном времени, вызовам для извлечения документов и одноразовым запросам . Извлечение отдельных документов и одноразовые запросы можно рассматривать как кратковременные прослушиватели снимков, которые имеют схожие ограничения производительности.

Применяйте лучшие практики для масштабирования запросов в реальном времени

Применяйте следующие рекомендации для разработки масштабируемых запросов в реальном времени.

Понимание высокого трафика записи в системе

Этот раздел поможет вам понять, как система реагирует на растущее количество запросов на запись.

Журналы изменений Cloud Firestore , управляющие запросами в режиме реального времени, автоматически масштабируются горизонтально по мере увеличения трафика записи. Когда скорость записи в базу данных превышает возможности одного сервера, журнал изменений разделяется между несколькими серверами, и обработка запросов начинает использовать данные из нескольких обработчиков подписок вместо одного. С точки зрения клиента и SDK всё это прозрачно, и никаких действий со стороны приложения при разделении не требуется. На следующей диаграмме показано, как масштабируются запросы в режиме реального времени:

Архитектура разветвления журнала изменений

Автоматическое масштабирование позволяет увеличивать трафик записи без ограничений, но по мере роста трафика системе может потребоваться некоторое время для ответа. Следуйте рекомендациям правила «5-5-5» , чтобы избежать создания точек перегрузки при записи. Key Visualizer — полезный инструмент для анализа точек перегрузки при записи.

Многие приложения демонстрируют предсказуемый органический рост, который Cloud Firestore может обеспечить без каких-либо мер предосторожности. Однако пакетные нагрузки, такие как импорт больших наборов данных, могут привести к слишком быстрому росту числа записей. При проектировании приложения обращайте внимание на источники трафика записи.

Понять, как взаимодействуют записи и чтения

Систему запросов в реальном времени можно представить как конвейер, соединяющий операции записи с операциями чтения. При создании, обновлении или удалении документа изменение распространяется из системы хранения к зарегистрированным в данный момент слушателям. Структура журнала изменений Cloud Firestore гарантирует строгую согласованность, то есть ваше приложение никогда не получит уведомления об обновлениях, порядок которых нарушен по сравнению с моментом фиксации изменений базой данных. Это упрощает разработку приложений, устраняя граничные случаи, связанные с согласованностью данных.

Этот связанный конвейер означает, что операция записи, вызывающая перегрузки или конфликты блокировок, может негативно повлиять на операции чтения. В случае сбоя или ограничения скорости записи чтение может остановиться в ожидании согласованных данных из журнала изменений. Если это происходит в вашем приложении, вы можете столкнуться как с медленными операциями записи, так и с коррелированным медленным временем ответа на запросы. Ключ к предотвращению этой проблемы — предотвращение перегрузок.

Соблюдайте краткий объем документов и операций записи.

При создании приложений с прослушивателями снимков обычно требуется, чтобы пользователи быстро узнавали об изменениях данных. Для этого старайтесь, чтобы данные были небольшими. Система может очень быстро обрабатывать небольшие документы с десятками полей. Обработка более крупных документов с сотнями полей и большим объёмом данных занимает больше времени.

Аналогично, отдавайте предпочтение коротким и быстрым операциям фиксации и записи, чтобы минимизировать задержку. Большие пакеты могут обеспечить более высокую пропускную способность с точки зрения записи, но на самом деле могут увеличить время оповещения для прослушивателей снимков. Это часто противоречит здравому смыслу по сравнению с использованием других систем баз данных, где пакетная обработка может использоваться для повышения производительности.

Используйте эффективных слушателей

По мере увеличения скорости записи в вашу базу данных Cloud Firestore распределяет обработку данных между несколькими серверами. Алгоритм шардинга Cloud Firestore старается разместить данные из одной коллекции или группы коллекций на одном сервере журнала изменений. Система стремится максимально увеличить пропускную способность записи, сохраняя при этом минимальное количество серверов, участвующих в обработке запроса.

Однако некоторые закономерности всё ещё могут приводить к неоптимальному поведению прослушивателей снимков. Например, если ваше приложение хранит большую часть данных в одной большой коллекции, прослушивателю может потребоваться подключение ко многим серверам для получения всех необходимых данных. Это остаётся актуальным даже при применении фильтра запросов. Подключение ко многим серверам увеличивает риск замедления отклика.

Чтобы избежать этих более медленных ответов, спроектируйте схему и приложение таким образом, чтобы система могла обслуживать слушателей, не обращаясь ко множеству разных серверов. Возможно, лучше всего будет разбить данные на более мелкие коллекции с меньшей скоростью записи.

Это похоже на анализ производительности запросов в реляционной базе данных, требующих полного сканирования таблиц. В реляционной базе данных запрос, требующий полного сканирования таблиц, эквивалентен прослушивателю снимков, отслеживающему коллекцию с высокой частотой обновления. Он может выполняться медленнее по сравнению с запросом, который база данных может обработать, используя более точный индекс. Запрос с более точным индексом подобен прослушивателю снимков, отслеживающему один документ или коллекцию, которая меняется реже. Вам следует провести нагрузочное тестирование своего приложения, чтобы лучше понять поведение и потребности вашего варианта использования.

Обеспечьте быструю обработку запросов на опрос

Ещё один ключевой аспект адаптивных запросов в реальном времени — обеспечение быстрого и эффективного выполнения опроса для загрузки данных. При первом подключении нового прослушивателя снимков он должен загрузить весь набор результатов и отправить его на устройство пользователя. Медленные запросы снижают скорость отклика вашего приложения. К ним относятся, например, запросы, пытающиеся прочитать много документов, или запросы, не использующие соответствующие индексы.

При некоторых обстоятельствах прослушиватель может также вернуться из состояния прослушивания в состояние опроса. Это происходит автоматически и незаметно для SDK и вашего приложения. Следующие условия могут вызвать переход в состояние опроса:

  • Система перебалансирует журнал изменений из-за изменений нагрузки.
  • Горячие точки приводят к сбоям или задержкам записи в базу данных.
  • Временные перезагрузки сервера временно влияют на слушателей.

Если ваши опросы выполняются достаточно быстро, состояние опроса становится прозрачным для пользователей вашего приложения.

Отдавайте предпочтение долгоживущим слушателям

Открытие и поддержание активности прослушивателей как можно дольше часто является наиболее экономичным способом создания приложения, использующего Cloud Firestore . При использовании Cloud Firestore с вас взимается плата за возвращаемые приложению документы, а не за поддержание открытого соединения. Долгоживущий прослушиватель снимков считывает только те данные, которые необходимы для обслуживания запроса в течение всего его жизненного цикла. Это включает в себя первоначальный опрос и уведомления об изменении данных. Однократные запросы, с другой стороны, повторно считывают данные, которые могли не измениться с момента последнего выполнения запроса приложением.

В случаях, когда ваше приложение должно потреблять большой объём данных, прослушиватели снимков могут быть неподходящими. Например, если ваш сценарий использования предполагает отправку большого количества документов в секунду через соединение в течение длительного периода времени, может быть лучше выбрать одноразовые запросы, выполняемые с меньшей частотой.

Что дальше?