Рекомендации по работе с Cloud Firestore

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

Местоположение базы данных

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

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

Выберите региональное местоположение, чтобы снизить расходы, уменьшить задержку записи (если это важно для вашего приложения) или разместить данные вместе с другими ресурсами GCP.

Идентификаторы документов

  • Не используйте идентификаторы документов . и ...
  • Не используйте косую черту / в идентификаторах документов.
  • Не используйте монотонно возрастающие идентификаторы документов, например:

    • Customer1, Customer2, Customer3, ...
    • Product 1, Product 2, Product 3, ...

    Такие последовательные идентификаторы могут привести к возникновению горячих точек, которые влияют на задержку.

Названия полей

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

    • . точка
    • [ левая квадратная скобка
    • ] правая квадратная скобка
    • * звездочка
    • ` обратный апостроф

Индексы

Уменьшение задержки записи

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

  • Настройте исключения из индекса на уровне коллекции. Проще всего отключить индексирование по убыванию и индексирование массивов. Удаление неиспользуемых индексированных значений также снизит расходы на хранение.

  • Уменьшите количество документов в транзакции. Для записи большого количества документов рекомендуется использовать массовую запись вместо атомарной пакетной записи.

Исключения из индекса

Для большинства приложений можно использовать автоматическое индексирование, а также ссылки в сообщениях об ошибках. Однако в некоторых случаях может потребоваться добавить исключения для отдельных полей:

Падеж Описание
Большие строковые поля

Если у вас есть строковое поле, которое часто содержит длинные строковые значения, которые вы не используете для запросов, вы можете сократить расходы на хранение, исключив поле из индексации.

Высокая скорость записи в коллекцию, содержащую документы с последовательными значениями.

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

Например, в варианте использования IoT с высокой скоростью записи, коллекция, содержащая документы с полем временной метки, может приблизиться к лимиту в 500 записей в секунду.

Поля TTL

Если вы используете правила TTL (время жизни), обратите внимание, что поле TTL должно быть временной меткой. Индексирование полей TTL включено по умолчанию и может влиять на производительность при более высоких показателях трафика. Рекомендуем добавить исключения автоматического индексирования для полей TTL.

Большие массивы или поля карт

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

Операции чтения и записи

  • Точная максимальная частота, с которой приложение может обновлять один документ, в значительной степени зависит от рабочей нагрузки. Подробнее об обновлении одного документа…

  • По возможности используйте асинхронные вызовы вместо синхронных. Асинхронные вызовы минимизируют влияние на задержку. Например, рассмотрим приложение, которому для отображения ответа требуются результаты поиска документа и результаты запроса. Если между поиском и запросом нет зависимости данных, нет необходимости синхронно ждать завершения поиска, прежде чем инициировать запрос.

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

Повторные попытки транзакций

SDK и клиентские библиотеки Cloud Firestore автоматически повторяют неудачные транзакции, чтобы устранить временные ошибки. Если ваше приложение обращается к Cloud Firestore напрямую через API REST или RPC, а не через SDK, то для повышения надежности в нем следует реализовать повторные попытки транзакций.

Оповещения об обновлениях

Рекомендации по работе с обновлениями в реальном времени приведены в статье Как работать с запросами в реальном времени.

Проектирование для масштабирования

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

Обновления в одном документе

При разработке приложения учитывайте, как быстро оно обновляет отдельные документы. Лучший способ оценить производительность рабочей нагрузки – провести нагрузочное тестирование. Точная максимальная частота, с которой приложение может обновлять один документ, в значительной степени зависит от рабочей нагрузки. К таким факторам относятся скорость записи, конкуренция между запросами и количество затронутых индексов.

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

Высокая частота чтения, записи и удаления в узком диапазоне документов.

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

  • Создает новые документы с очень высокой скоростью и присваивает им собственные монотонно возрастающие идентификаторы.

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

  • создает новые документы с высокой скоростью в коллекции с небольшим количеством документов;

  • Создает новые документы с монотонно возрастающим полем, например временной меткой, с очень высокой скоростью.

  • Быстро удаляет документы из коллекции.

  • Запись в базу данных выполняется с очень высокой скоростью без постепенного увеличения трафика.

Не пропускайте удаленные данные

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

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

docs = db.collection('WorkItems').order_by('created').limit(100)
delete_batch = db.batch()
for doc in docs.stream():
  finish_work(doc)
  delete_batch.delete(doc.reference)
delete_batch.commit()

При каждом выполнении этого запроса он сканирует записи индекса для поля created в любых недавно удаленных документах. Это замедляет выполнение запросов.

Чтобы повысить эффективность, используйте метод start_at. Пример:

completed_items = db.collection('CompletionStats').document('all stats').get()
docs = db.collection('WorkItems').start_at(
    {'created': completed_items.get('last_completed')}).order_by(
        'created').limit(100)
delete_batch = db.batch()
last_completed = None
for doc in docs.stream():
  finish_work(doc)
  delete_batch.delete(doc.reference)
  last_completed = doc.get('created')

if last_completed:
  delete_batch.update(completed_items.reference,
                      {'last_completed': last_completed})
  delete_batch.commit()

ПРИМЕЧАНИЕ. В примере выше используется монотонно возрастающее поле, которое является антипаттерном для высокой скорости записи.

Увеличение трафика

Вам следует постепенно увеличивать трафик к новым коллекциям или лексикографически близким документам, чтобы у Cloud Firestore было достаточно времени для подготовки документов к увеличению трафика. Рекомендуем начать с 500 операций в секунду для новой коллекции, а затем увеличивать трафик на 50 % каждые 5 минут. Аналогичным образом можно увеличить трафик записи, но не забывайте о стандартных ограничениях Cloud Firestore. Убедитесь, что операции распределены относительно равномерно по всему диапазону ключей. Это называется правилом "500/50/5".

Перенос трафика в новую коллекцию

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

Похожая проблема может возникнуть, если вы измените идентификаторы многих документов в одной коллекции.

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

Параллельное чтение

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

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

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

Усовершенствованный вариант этой стратегии – перенос небольших групп пользователей по очереди. Добавьте в документ пользователя поле, в котором будет отслеживаться статус переноса данных этого пользователя. Выберите группу пользователей для переноса на основе хеша идентификатора пользователя. Используйте пакетное задание, чтобы перенести документы для этой группы пользователей, и параллельное чтение для пользователей, чьи данные находятся в процессе переноса.

Обратите внимание, что откат будет затруднен, если вы не будете выполнять двойную запись старых и новых объектов на этапе переноса. Это увеличит расходы на Cloud Firestore.

Конфиденциальность

  • Не храните конфиденциальную информацию в идентификаторе проекта Google Cloud. Идентификатор проекта Cloud может храниться дольше, чем существует сам проект.
  • Чтобы обеспечить соответствие требованиям к данным, мы рекомендуем не хранить конфиденциальную информацию в названиях документов и полей.

Защита от несанкционированного доступа

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

Подробнее о том, как использовать Cloud Firestore Security Rules…