Используйте рекомендации, перечисленные здесь, в качестве краткого справочника при создании приложения, использующего 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 через REST или RPC API напрямую, а не через 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.
Предотвращение несанкционированного доступа
Предотвратите несанкционированные операции с вашей базой данных с помощью правил безопасности Cloud Firestore. Например, с помощью правил можно избежать ситуации, когда злоумышленник неоднократно загружает всю вашу базу данных.
Узнайте больше об использовании правил безопасности Cloud Firestore .