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