Лучшие практики для Cloud Firestore

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

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

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

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

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

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

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

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

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

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

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

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

Индексы

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

Основной вклад в задержку записи вносит индексный разветвитель. Лучшие практики для уменьшения индексного разветвителя:

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

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

Индексные исключения

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

Случай Описание
Большие поля струн

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

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

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

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

TTL-поля

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

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

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

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

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

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

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

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

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

Обновления в реальном времени

Для получения информации о передовых методах, связанных с обновлениями в реальном времени, см. раздел Понимание масштабируемых запросов в реальном времени .

Проектирование с учетом масштаба

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

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

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

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

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

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

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

    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 .

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

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

Предотвратить несанкционированный доступ

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

Узнайте больше об использовании Cloud Firestore Security Rules .