Ознакомьтесь с этим документом, чтобы принимать обоснованные решения по проектированию архитектуры ваших приложений для обеспечения высокой производительности и надежности. Этот документ содержит расширенные темы, касающиеся Cloud Firestore . Если вы только начинаете работать с Cloud Firestore , обратитесь к краткому руководству .
Cloud Firestore — это гибкая, масштабируемая база данных для разработки мобильных приложений, веб-сайтов и серверов от Firebase и Google Cloud . Начать работу с Cloud Firestore и создавать многофункциональные и мощные приложения очень просто.
Чтобы ваши приложения продолжали эффективно работать по мере увеличения размера базы данных и трафика, полезно понимать механику операций чтения и записи в бэкэнде Cloud Firestore . Также необходимо понимать взаимодействие операций чтения и записи с уровнем хранения и основные ограничения, которые могут влиять на производительность.
Перед разработкой архитектуры приложения ознакомьтесь с рекомендациями в следующих разделах.
Разберитесь в компонентах высокого уровня.
На следующей диаграмме показаны основные компоненты, участвующие в запросе к API Cloud Firestore .

SDK и клиентские библиотеки Cloud Firestore
Cloud Firestore поддерживает SDK и клиентские библиотеки для различных платформ. Хотя приложение может напрямую обращаться к API Cloud Firestore по протоколам HTTP и RPC, клиентские библиотеки обеспечивают уровень абстракции, упрощающий использование API и позволяющий внедрять лучшие практики. Они также могут предоставлять дополнительные функции, такие как автономный доступ, кэширование и так далее.
Google Front End (GFE)
Это инфраструктурный сервис, общий для всех облачных сервисов Google. GFE принимает входящие запросы и перенаправляет их в соответствующий сервис Google (в данном контексте — в сервис Cloud Firestore ). Он также предоставляет другие важные функции, включая защиту от атак типа «отказ в обслуживании» (DoS).
Сервис Cloud Firestore
Сервис Cloud Firestore выполняет проверки API-запросов, включая аутентификацию, авторизацию, проверку квот и правила безопасности, а также управляет транзакциями. Этот сервис Cloud Firestore включает в себя клиент хранилища , который взаимодействует с уровнем хранилища для чтения и записи данных.
Уровень хранения Cloud Firestore
Уровень хранения Cloud Firestore отвечает за хранение как данных, так и метаданных, а также связанных с ними функций базы данных, предоставляемых Cloud Firestore . В следующих разделах описывается, как организованы данные на уровне хранения Cloud Firestore и как масштабируется система. Изучение организации данных поможет вам разработать масштабируемую модель данных и лучше понять лучшие практики работы с Cloud Firestore .
Ключевые диапазоны и разделения
Cloud Firestore — это NoSQL-база данных, ориентированная на документы. Данные хранятся в документах , которые организованы в иерархии коллекций . Иерархия коллекций и идентификатор документа преобразуются в единый ключ для каждого документа. Документы логически хранятся и упорядочиваются лексикографически по этому единственному ключу. Термин «диапазон ключей» используется для обозначения лексикографически непрерывного диапазона ключей.
Типичная база данных Cloud Firestore слишком велика, чтобы поместиться на одной физической машине. Также существуют сценарии, когда нагрузка на данные слишком велика для обработки одной машиной. Для обработки больших объемов данных Cloud Firestore разделяет данные на отдельные части, которые могут храниться и предоставляться с нескольких машин или серверов хранения . Эти разделы создаются в таблицах базы данных в виде блоков диапазонов ключей, называемых разбиениями.
Синхронная репликация
Важно отметить, что база данных всегда автоматически и синхронно реплицируется. Разделы данных имеют реплики в разных зонах , чтобы обеспечить их доступность даже в случае недоступности какой-либо зоны. Согласованная репликация на разные копии раздела управляется алгоритмом консенсуса Paxos . Одна реплика каждого раздела выбирается в качестве лидера Paxos, который отвечает за обработку операций записи в этот раздел. Синхронная репликация позволяет всегда иметь возможность читать самую последнюю версию данных из Cloud Firestore .
В результате получается масштабируемая и высокодоступная система, обеспечивающая низкую задержку как при чтении, так и при записи, независимо от высокой нагрузки и в очень больших масштабах.
Структура данных
Cloud Firestore — это документоориентированная база данных без схемы. Однако внутри она хранит данные преимущественно в двух таблицах, построенных по принципу реляционных баз данных, на уровне хранилища следующим образом:
- Таблица «Документы» : В этой таблице хранятся документы.
- Таблица индексов : В этой таблице хранятся записи индексов, позволяющие эффективно получать результаты, отсортированные по значению индекса.
На следующей диаграмме показано, как могут выглядеть таблицы базы данных Cloud Firestore с учетом разделения на зоны. Разделения реплицируются в трех разных зонах, и каждому разделению назначен лидер Paxos.

Один регион против нескольких регионов
При создании базы данных необходимо выбрать регион или несколько регионов .
Отдельный региональный локационный узел — это конкретное географическое местоположение, например, us-west1 . Разделение данных в базе данных Cloud Firestore имеет реплики в разных зонах внутри выбранного региона, как объяснялось ранее.
Многорегиональное размещение представляет собой определенный набор регионов, где хранятся реплики базы данных. В многорегиональной конфигурации Cloud Firestore два региона содержат полные реплики всех данных базы данных. Третий регион имеет реплику-свидетель , которая не хранит полный набор данных, но участвует в репликации. Благодаря репликации данных между несколькими регионами, данные остаются доступными для записи и чтения даже при потере данных в одном из регионов.
Для получения более подробной информации о местоположении региона см. раздел «Местоположение Cloud Firestore .

Понимание жизненного цикла операции записи в Cloud Firestore
Клиент Cloud Firestore может записывать данные, создавая, обновляя или удаляя один документ. Запись в один документ требует атомарного обновления как самого документа, так и связанных с ним записей индекса на уровне хранения. Cloud Firestore также поддерживает атомарные операции, состоящие из нескольких операций чтения и/или записи в один или несколько документов.
Для всех типов операций записи Cloud Firestore обеспечивает свойства ACID (атомарность, согласованность, изоляция и надежность), характерные для реляционных баз данных. Cloud Firestore также обеспечивает сериализуемость , что означает, что все транзакции отображаются так, как если бы они выполнялись последовательно.
Основные этапы транзакции записи
Когда клиент Cloud Firestore выполняет операцию записи или подтверждает транзакцию, используя любой из упомянутых ранее методов, внутри системы это выполняется как транзакция чтения-записи в базе данных на уровне хранения. Эта транзакция позволяет Cloud Firestore обеспечивать свойства ACID, упомянутые ранее.
В качестве первого шага транзакции Cloud Firestore считывает существующий документ и определяет, какие изменения необходимо внести в данные в таблице Documents.
Это также включает в себя внесение необходимых изменений в таблицу Indexes следующим образом:
- Для полей, добавляемых в документы, необходимо выполнить соответствующие вставки в таблицу «Индексы».
- Для полей, удаляемых из документов, необходимо выполнить соответствующее удаление в таблице «Индексы».
- Для полей в документах, подвергающихся изменению, необходимо выполнить как удаление (для старых значений), так и вставку (для новых значений) в таблицу Indexes.
Для вычисления упомянутых ранее изменений Cloud Firestore считывает конфигурацию индексирования базы данных. Конфигурация индексирования хранит информацию об индексах для базы данных. Cloud Firestore использует два типа индексов: однопольные и составные. Для более подробного понимания индексов, создаваемых в Cloud Firestore , см. раздел «Типы индексов в Cloud Firestore .
После вычисления изменений Cloud Firestore собирает их в транзакцию, а затем фиксирует её.
Разберитесь в транзакции записи на уровне хранения данных.
Как обсуждалось ранее, операция записи в Cloud Firestore включает в себя транзакцию чтения-записи на уровне хранилища. В зависимости от структуры данных, запись может включать одно или несколько разделений, как показано на схеме структуры данных .
На следующей диаграмме база данных Cloud Firestore имеет восемь разделов (обозначенных цифрами 1-8), размещенных на трех разных серверах хранения в одной зоне, и каждый раздел реплицируется в 3 (или более) разных зонах. У каждого раздела есть лидер Paxos, который может находиться в разных зонах для разных разделов.
Разделение базы данных Cloud Firestore">
Рассмотрим базу данных Cloud Firestore , содержащую коллекцию Restaurants следующего вида:

Клиент Cloud Firestore запрашивает следующее изменение в документе из коллекции Restaurant , обновляя значение поля priceCategory .

Следующие основные шаги описывают то, что происходит в процессе записи:
- Создайте транзакцию чтения и записи.
- Прочитайте документ
restaurant1из коллекцииRestaurantsиз таблицы Documents на уровне хранилища. - Прочитайте оглавление документа из таблицы «Оглавления» .
- Вычислите количество изменений, которые необходимо внести в данные. В данном случае имеется пять изменений:
- M1: Обновите строку для
restaurant1в таблице «Документы» , чтобы отразить изменение значения поляpriceCategory. - M2 и M3: Удалите строки со старым значением
priceCategoryв таблице Indexes для убывающих и возрастающих индексов. - M4 и M5: Вставьте строки с новым значением
priceCategoryв таблицу Indexes для убывающих и возрастающих индексов.
- M1: Обновите строку для
- Произведите эти мутации.
Клиент хранилища в сервисе Cloud Firestore ищет разделы, которым принадлежат ключи строк, подлежащих изменению. Рассмотрим случай, когда раздел 3 обслуживает M1, а раздел 6 — M2-M5. Происходит распределенная транзакция, в которой все эти разделы выступают в качестве участников . В число участвующих разделов могут также входить любые другие разделы, из которых данные были ранее прочитаны в рамках транзакции чтения-записи.
Следующие шаги описывают, что происходит в процессе фиксации изменений:
- Клиент хранилища отправляет команду commit. Команда commit содержит изменения M1-M5.
- В данной транзакции участвуют группы 3 и 6. Один из участников выбирается в качестве координатора , например, группа 3. Задача координатора — обеспечить атомарное завершение или прерывание транзакции всеми участниками.
- Руководители, выполняющие функции координаторов в этих группах, несут ответственность за работу, проделанную участниками и координаторами.
- Каждый участник и координатор запускает алгоритм Paxos со своими соответствующими репликами.
- Лидер запускает алгоритм Paxos с репликами. Кворум достигается, если большинство реплик отвечают лидеру подтверждением
ok to commit. - Затем каждый участник уведомляет координатора о своей готовности (первый этап двухэтапной фиксации). Если какой-либо участник не может зафиксировать транзакцию, вся транзакция
aborts.
- Лидер запускает алгоритм Paxos с репликами. Кворум достигается, если большинство реплик отвечают лидеру подтверждением
- Как только координатор убедится, что все участники, включая его самого, готовы, он сообщает всем участникам о
acceptтранзакции (вторая фаза двухфазной фиксации). На этой фазе каждый участник записывает решение о фиксации в стабильное хранилище, и транзакция фиксируется. - Координатор отправляет клиенту хранилища в Cloud Firestore подтверждение о том, что транзакция зафиксирована. Параллельно координатор и все участники применяют изменения к данным.

Когда база данных Cloud Firestore невелика, может случиться так, что один раздел будет владеть всеми ключами в транзакциях M1-M5. В таком случае в транзакции участвует только один участник, и упомянутая ранее двухфазная фиксация не требуется, что ускоряет запись.
Запись в нескольких регионах
В многорегиональной конфигурации распределение реплик по регионам повышает доступность, но сопряжено с ухудшением производительности. Время обмена данными между репликами в разных регионах увеличивается. Следовательно, базовая задержка для операций Cloud Firestore несколько выше по сравнению с однорегиональными конфигурациями.
Мы настраиваем реплики таким образом, чтобы лидерство при разделении данных всегда оставалось за основным регионом. Основной регион — это тот, из которого трафик поступает на сервер Cloud Firestore . Такое решение о лидерстве уменьшает задержку обмена данными между клиентом хранилища в Cloud Firestore и лидером реплики (или координатором для транзакций с множественным разделением).
Каждая операция записи в Cloud Firestore также включает в себя некоторое взаимодействие с механизмом обработки запросов в реальном времени в Cloud Firestore . Для получения дополнительной информации о запросах в реальном времени см. раздел «Понимание запросов в реальном времени в масштабе» .
Поймите жизненный цикл чтения в Cloud Firestore
В этом разделе рассматриваются автономные операции чтения, не требующие обработки в реальном времени, в Cloud Firestore . Внутри системы сервер Cloud Firestore обрабатывает большинство таких запросов в два основных этапа:
- Однократное сканирование диапазона по таблице индексов.
- Точечный поиск в таблице «Документы» на основе результатов предыдущего сканирования.
Чтение данных из уровня хранения осуществляется внутри системы с использованием транзакций базы данных для обеспечения согласованности чтения. Однако, в отличие от транзакций, используемых для записи, эти транзакции не используют блокировки. Вместо этого они работают путем выбора временной метки, а затем выполнения всех операций чтения в эту временную метку. Поскольку они не получают блокировок, они не блокируют одновременные операции чтения и записи. Для выполнения этой транзакции клиент хранения в Cloud Firestore указывает временную метку, которая сообщает уровню хранения, как выбрать временную метку для чтения. Тип временной метки, выбранной клиентом хранения в Cloud Firestore , определяется параметрами чтения для запроса на чтение.
Понимание транзакции чтения на уровне хранения данных.
В этом разделе описываются типы операций чтения и способы их обработки на уровне хранения данных в Cloud Firestore .
Увлекательное чтение
По умолчанию чтение Cloud Firestore осуществляется с использованием строгой согласованности . Эта строгая согласованность означает, что при чтении из Cloud Firestore возвращается последняя версия данных, отражающая все операции записи, выполненные до начала чтения.
Однократное раздельное чтение
Клиент хранилища в Cloud Firestore находит разделы, которым принадлежат ключи строк, подлежащих чтению. Предположим, ему нужно прочитать данные из раздела 3 из предыдущего раздела . Клиент отправляет запрос на чтение ближайшей реплике, чтобы уменьшить задержку при передаче запроса туда и обратно.
На данном этапе в зависимости от выбранной реплики могут произойти следующие события:
- Запрос на чтение направляется ведущей реплике (зона А).
- Поскольку ведущий всегда в курсе последних событий, чтение может продолжаться без остановок.
- Запрос на чтение направляется реплике, не являющейся лидером (например, в Зону B).
- Split 3, возможно, по своему внутреннему состоянию знает, что у него достаточно информации для выполнения операции чтения, и Split это делает.
- Split 3 не уверен, получил ли он последние данные. Он отправляет сообщение лидеру с просьбой указать метку времени последней транзакции, которую необходимо применить для обработки запроса на чтение. После применения этой транзакции чтение может быть продолжено.
Затем Cloud Firestore возвращает ответ своему клиенту.
Многократное разделение чтения
В ситуации, когда чтение необходимо выполнить из нескольких разделов данных, для всех разделов используется один и тот же механизм. После того, как данные будут получены из всех разделов, клиент хранилища в Cloud Firestore объединяет результаты. Затем Cloud Firestore отправляет эти данные своему клиенту.
Заезженные книги
В Cloud Firestore режим чтения по умолчанию — это режим «быстрого чтения». Однако он сопряжен с потенциально большей задержкой из-за необходимости обмена данными с лидером. Часто вашему приложению Cloud Firestore не требуется считывать последнюю версию данных, и эта функция хорошо работает с данными, которые могут быть устаревшими на несколько секунд.
В таком случае клиент может выбрать получение устаревших данных, используя параметр чтения read_time . В этом случае чтение выполняется в том виде, в котором данные были на момент read_time , и ближайшая реплика, скорее всего, уже подтвердила наличие данных на указанный момент read_time . Для заметно более высокой производительности разумным значением для учета устаревших данных является 15 секунд. Даже для устаревших данных возвращаемые строки будут согласованы друг с другом.
Избегайте зон повышенного риска
В Cloud Firestore распределение трафика происходит автоматически, разбивая его на более мелкие части, чтобы при необходимости или при расширении пространства ключей распределить нагрузку по серверам хранения. Части, созданные для обработки избыточного трафика, сохраняются примерно 24 часа, даже если трафик пропадает. Таким образом, при повторяющихся всплесках трафика разделение сохраняется, и при необходимости вводятся новые части. Эти механизмы помогают базам данных Cloud Firestore автоматически масштабироваться при увеличении нагрузки трафика или размера базы данных. Однако следует учитывать некоторые ограничения, описанные ниже.
Разделение хранилища и нагрузки требует времени, а слишком быстрое увеличение трафика может привести к высокой задержке или ошибкам превышения сроков, обычно называемым «горячими точками» , пока сервис адаптируется. Наилучшей практикой является распределение операций по диапазону ключей, при этом наращивая трафик на коллекции в базе данных с частотой 500 операций в секунду. После этого постепенного увеличения трафик следует наращивать до 50% каждые пять минут. Этот процесс называется правилом 500/50/5 и позволяет оптимально масштабировать базу данных в соответствии с вашей рабочей нагрузкой.
Хотя при увеличении нагрузки разделение данных происходит автоматически, Cloud Firestore может разделить диапазон ключей только до тех пор, пока не будет обслуживаться один документ с использованием выделенного набора реплицированных серверов хранения. В результате, большие и постоянные объемы одновременных операций над одним документом могут привести к возникновению «горячей точки» в этом документе. Если вы сталкиваетесь с устойчиво высокими задержками при работе с одним документом, вам следует рассмотреть возможность изменения вашей модели данных для разделения или репликации данных между несколькими документами.
Ошибки конкуренции возникают, когда несколько операций пытаются одновременно читать и/или записывать один и тот же документ.
Еще один особый случай возникновения «горячих точек» происходит, когда в качестве идентификатора документа в Cloud Firestore используется ключ с последовательным увеличением/уменьшением, и при этом выполняется значительно больше операций в секунду. Создание дополнительных разделов здесь не помогает, поскольку всплеск трафика просто перемещается в вновь созданный раздел. Поскольку Cloud Firestore по умолчанию автоматически индексирует все поля документа, такие движущиеся «горячие точки» могут также создаваться в индексном пространстве для поля документа, содержащего значение с последовательным увеличением/уменьшением, например, метку времени.
Обратите внимание, что, следуя описанным выше рекомендациям, Cloud Firestore сможет масштабироваться для обслуживания произвольно больших рабочих нагрузок без необходимости корректировки каких-либо настроек.
Поиск неисправностей
Cloud Firestore предоставляет Key Visualizer в качестве диагностического инструмента, предназначенного для анализа моделей использования и устранения проблем, связанных с возникновением «горячих точек».
Что дальше?
- Узнайте больше о передовых методах.
- Узнайте о запросах в реальном времени в масштабе предприятия.
Ознакомьтесь с этим документом, чтобы принимать обоснованные решения по проектированию архитектуры ваших приложений для обеспечения высокой производительности и надежности. Этот документ содержит расширенные темы, касающиеся Cloud Firestore . Если вы только начинаете работать с Cloud Firestore , обратитесь к краткому руководству .
Cloud Firestore — это гибкая, масштабируемая база данных для разработки мобильных приложений, веб-сайтов и серверов от Firebase и Google Cloud . Начать работу с Cloud Firestore и создавать многофункциональные и мощные приложения очень просто.
Чтобы ваши приложения продолжали эффективно работать по мере увеличения размера базы данных и трафика, полезно понимать механику операций чтения и записи в бэкэнде Cloud Firestore . Также необходимо понимать взаимодействие операций чтения и записи с уровнем хранения и основные ограничения, которые могут влиять на производительность.
Перед разработкой архитектуры приложения ознакомьтесь с рекомендациями в следующих разделах.
Разберитесь в компонентах высокого уровня.
На следующей диаграмме показаны основные компоненты, участвующие в запросе к API Cloud Firestore .

SDK и клиентские библиотеки Cloud Firestore
Cloud Firestore поддерживает SDK и клиентские библиотеки для различных платформ. Хотя приложение может напрямую обращаться к API Cloud Firestore по протоколам HTTP и RPC, клиентские библиотеки обеспечивают уровень абстракции, упрощающий использование API и позволяющий внедрять лучшие практики. Они также могут предоставлять дополнительные функции, такие как автономный доступ, кэширование и так далее.
Google Front End (GFE)
Это инфраструктурный сервис, общий для всех облачных сервисов Google. GFE принимает входящие запросы и перенаправляет их в соответствующий сервис Google (в данном контексте — в сервис Cloud Firestore ). Он также предоставляет другие важные функции, включая защиту от атак типа «отказ в обслуживании» (DoS).
Сервис Cloud Firestore
Сервис Cloud Firestore выполняет проверки API-запросов, включая аутентификацию, авторизацию, проверку квот и правила безопасности, а также управляет транзакциями. Этот сервис Cloud Firestore включает в себя клиент хранилища , который взаимодействует с уровнем хранилища для чтения и записи данных.
Уровень хранения Cloud Firestore
Уровень хранения Cloud Firestore отвечает за хранение как данных, так и метаданных, а также связанных с ними функций базы данных, предоставляемых Cloud Firestore . В следующих разделах описывается, как организованы данные на уровне хранения Cloud Firestore и как масштабируется система. Изучение организации данных поможет вам разработать масштабируемую модель данных и лучше понять лучшие практики работы с Cloud Firestore .
Ключевые диапазоны и разделения
Cloud Firestore — это NoSQL-база данных, ориентированная на документы. Данные хранятся в документах , которые организованы в иерархии коллекций . Иерархия коллекций и идентификатор документа преобразуются в единый ключ для каждого документа. Документы логически хранятся и упорядочиваются лексикографически по этому единственному ключу. Термин «диапазон ключей» используется для обозначения лексикографически непрерывного диапазона ключей.
Типичная база данных Cloud Firestore слишком велика, чтобы поместиться на одной физической машине. Также существуют сценарии, когда нагрузка на данные слишком велика для обработки одной машиной. Для обработки больших объемов данных Cloud Firestore разделяет данные на отдельные части, которые могут храниться и предоставляться с нескольких машин или серверов хранения . Эти разделы создаются в таблицах базы данных в виде блоков диапазонов ключей, называемых разбиениями.
Синхронная репликация
Важно отметить, что база данных всегда автоматически и синхронно реплицируется. Разделы данных имеют реплики в разных зонах , чтобы обеспечить их доступность даже в случае недоступности какой-либо зоны. Согласованная репликация на разные копии раздела управляется алгоритмом консенсуса Paxos . Одна реплика каждого раздела выбирается в качестве лидера Paxos, который отвечает за обработку операций записи в этот раздел. Синхронная репликация позволяет всегда иметь возможность читать самую последнюю версию данных из Cloud Firestore .
В результате получается масштабируемая и высокодоступная система, обеспечивающая низкую задержку как при чтении, так и при записи, независимо от высокой нагрузки и в очень больших масштабах.
Структура данных
Cloud Firestore — это документоориентированная база данных без схемы. Однако внутри она хранит данные преимущественно в двух таблицах, построенных по принципу реляционных баз данных, на уровне хранилища следующим образом:
- Таблица «Документы» : В этой таблице хранятся документы.
- Таблица индексов : В этой таблице хранятся записи индексов, позволяющие эффективно получать результаты, отсортированные по значению индекса.
На следующей диаграмме показано, как могут выглядеть таблицы базы данных Cloud Firestore с учетом разделения на зоны. Разделения реплицируются в трех разных зонах, и каждому разделению назначен лидер Paxos.

Один регион против нескольких регионов
При создании базы данных необходимо выбрать регион или несколько регионов .
Отдельный региональный локационный узел — это конкретное географическое местоположение, например, us-west1 . Разделение данных в базе данных Cloud Firestore имеет реплики в разных зонах внутри выбранного региона, как объяснялось ранее.
Многорегиональное размещение представляет собой определенный набор регионов, где хранятся реплики базы данных. В многорегиональной конфигурации Cloud Firestore два региона содержат полные реплики всех данных базы данных. Третий регион имеет реплику-свидетель , которая не хранит полный набор данных, но участвует в репликации. Благодаря репликации данных между несколькими регионами, данные остаются доступными для записи и чтения даже при потере данных в одном из регионов.
Для получения более подробной информации о местоположении региона см. раздел «Местоположение Cloud Firestore .

Понимание жизненного цикла операции записи в Cloud Firestore
Клиент Cloud Firestore может записывать данные, создавая, обновляя или удаляя один документ. Запись в один документ требует атомарного обновления как самого документа, так и связанных с ним записей индекса на уровне хранения. Cloud Firestore также поддерживает атомарные операции, состоящие из нескольких операций чтения и/или записи в один или несколько документов.
Для всех типов операций записи Cloud Firestore обеспечивает свойства ACID (атомарность, согласованность, изоляция и надежность), характерные для реляционных баз данных. Cloud Firestore также обеспечивает сериализуемость , что означает, что все транзакции отображаются так, как если бы они выполнялись последовательно.
Основные этапы транзакции записи
Когда клиент Cloud Firestore выполняет операцию записи или подтверждает транзакцию, используя любой из упомянутых ранее методов, внутри системы это выполняется как транзакция чтения-записи в базе данных на уровне хранения. Эта транзакция позволяет Cloud Firestore обеспечивать свойства ACID, упомянутые ранее.
В качестве первого шага транзакции Cloud Firestore считывает существующий документ и определяет, какие изменения необходимо внести в данные в таблице Documents.
Это также включает в себя внесение необходимых изменений в таблицу Indexes следующим образом:
- Для полей, добавляемых в документы, необходимо выполнить соответствующие вставки в таблицу «Индексы».
- Для полей, удаляемых из документов, необходимо выполнить соответствующее удаление в таблице «Индексы».
- Для полей в документах, подвергающихся изменению, необходимо выполнить как удаление (для старых значений), так и вставку (для новых значений) в таблицу Indexes.
Для вычисления упомянутых ранее изменений Cloud Firestore считывает конфигурацию индексирования базы данных. Конфигурация индексирования хранит информацию об индексах для базы данных. Cloud Firestore использует два типа индексов: однопольные и составные. Для более подробного понимания индексов, создаваемых в Cloud Firestore , см. раздел «Типы индексов в Cloud Firestore .
После вычисления изменений Cloud Firestore собирает их в транзакцию, а затем фиксирует её.
Разберитесь в транзакции записи на уровне хранения данных.
Как обсуждалось ранее, операция записи в Cloud Firestore включает в себя транзакцию чтения-записи на уровне хранилища. В зависимости от структуры данных, запись может включать одно или несколько разделений, как показано на схеме структуры данных .
На следующей диаграмме база данных Cloud Firestore имеет восемь разделов (обозначенных цифрами 1-8), размещенных на трех разных серверах хранения в одной зоне, и каждый раздел реплицируется в 3 (или более) разных зонах. У каждого раздела есть лидер Paxos, который может находиться в разных зонах для разных разделов.
Разделение базы данных Cloud Firestore">
Рассмотрим базу данных Cloud Firestore , содержащую коллекцию Restaurants следующего вида:

Клиент Cloud Firestore запрашивает следующее изменение в документе из коллекции Restaurant , обновляя значение поля priceCategory .

Следующие основные шаги описывают то, что происходит в процессе записи:
- Создайте транзакцию чтения и записи.
- Прочитайте документ
restaurant1из коллекцииRestaurantsиз таблицы Documents на уровне хранилища. - Прочитайте оглавление документа из таблицы «Оглавления» .
- Вычислите количество изменений, которые необходимо внести в данные. В данном случае имеется пять изменений:
- M1: Update the row for
restaurant1in the Documents table to reflect the change in value of thepriceCategoryfield. - M2 and M3: Delete the rows for the old value of
priceCategoryin the Indexes table for descending and ascending indexes. - M4 and M5: Insert the rows for the new value of
priceCategoryin the Indexes table for descending and ascending indexes.
- M1: Update the row for
- Commit these mutations.
The storage client in the Cloud Firestore service looks up the splits that owns the keys of the rows to be changed. Let's consider a case where Split 3 serves M1, and Split 6 serves M2-M5. There is a distributed transaction, involving all these splits as participants . The participant splits may also include any other split from which data was read earlier as part of the read-write transaction.
The following steps describe what happens as part of the commit:
- The storage client issues a commit. The commit contains the mutations M1-M5.
- Splits 3 and 6 are the participants in this transaction. One of the participants is chosen as the coordinator , such as Split 3. The job of the coordinator is to make sure the transaction either commits or aborts atomically across all participants.
- The leader replicas of these splits are responsible for work done by the participants and coordinators.
- Each participant and coordinator runs a Paxos algorithm with their respective replicas.
- The leader runs a Paxos algorithm with the replicas. Quorum is achieved if most of the replicas reply with an
ok to commitresponse to the leader. - Each participant then notifies the coordinator when they are prepared (first phase of two-phase commit). If any participant cannot commit the transaction, the whole transaction
aborts.
- The leader runs a Paxos algorithm with the replicas. Quorum is achieved if most of the replicas reply with an
- Once the coordinator knows all participants, including itself, are prepared, it communicates the
accepttransaction outcome to all the participants (second phase of two-phase commit). In this phase, each participant records the commit decision to stable storage and the transaction is committed. - The coordinator responds to the storage client in Cloud Firestore that the transaction has been committed. In parallel, the coordinator and all the participants apply the mutations to the data.

When the Cloud Firestore database is small, it may happen that a single split owns all the keys in the mutations M1-M5. In such a case, there is only one participant in the transaction and the two-phase commit mentioned earlier is not required, thus making the writes faster.
Writes in multi-region
In a multi-region deployment, the spread of replicas across regions increases availability, but comes with a performance cost. The communication between replicas in different regions takes longer round trip times. Hence, the baseline latency for Cloud Firestore operations is slightly more compared to single region deployments.
We configure the replicas in a way that leadership for splits always stays in the primary region. The primary region is the one from which traffic is incoming to the Cloud Firestore server. This decision of leadership reduces the round-trip delay in communication between the storage client in Cloud Firestore and the replica leader (or coordinator for multi-split transactions).
Each write in Cloud Firestore also involves some interaction with the real-time engine in Cloud Firestore . For more information about real-time queries, see Understand real-time queries at scale .
Understand the life of a read in Cloud Firestore
This section delves into standalone, non-realtime reads in Cloud Firestore . Internally, the Cloud Firestore server handles most of these queries in two major stages:
- A single range scan over the Indexes table
- Point lookups in the Documents table based on the result of the earlier scan
The data reads from the storage layer are internally done by using a database transaction to ensure consistent reads. However, unlike the transactions used for writes, these transactions do not take locks. Instead, they work by choosing a timestamp, then executing all reads at that timestamp. Since they do not acquire locks, they do not block concurrent read-write transactions. To execute this transaction, the storage client in Cloud Firestore specifies a timestamp bound, which tells the storage layer how to choose a read timestamp. The type of timestamp bound chosen by the storage client in Cloud Firestore is determined by the read options for the Read request.
Understand a read transaction in the storage layer
This section describes the types of reads and how they are processed in the storage layer in Cloud Firestore .
Strong reads
By default, Cloud Firestore reads are strongly consistent . This strong consistency means that a Cloud Firestore read returns the latest version of the data that reflects all writes that have been committed up until the start of the read.
Single Split read
The storage client in Cloud Firestore looks up the splits that own the keys of the rows to be read. Let's assume that it needs to do a read from Split 3 from the earlier section . The client sends the read request to the nearest replica to reduce round trip latency.
At this point, the following cases might happen depending on the chosen replica:
- Read request goes to a leader replica (Zone A).
- As the leader is always up-to-date, the read can proceed directly.
- Read request goes to a non-leader replica (such as, Zone B)
- Split 3 may know by its internal state that it has enough information to serve the read and the split does so.
- Split 3 is unsure if it has seen the latest data. It sends a message to the leader to ask for the timestamp of the last transaction it needs to apply to serve the read. Once that transaction is applied, the read can proceed.
Cloud Firestore then returns the response to its client.
Multi-split read
In the situation where the reads have to be done from multiple splits, the same mechanism happens across all the splits. Once the data has been returned from all the splits, the storage client in Cloud Firestore combines the results. Cloud Firestore then responds to its client with this data.
Заезженные книги
Strong reads are the default mode in Cloud Firestore . However, it comes at a cost of potential higher latency due to the communication that may be required with the leader. Often your Cloud Firestore application doesn't need to read the latest version of the data and the functionality works well with data that may be a few seconds stale.
In such a case, the client may opt to receive stale reads by using the read_time read options. In this case, reads are done as the data was at read_time , and the closest replica is highly likely to already have verified it has data at the specified read_time . For noticeably better performance, 15 seconds is a reasonable staleness value. Even for stale reads, rows yielded are consistent with each other.
Avoid hotspots
The splits in Cloud Firestore are automatically broken into smaller pieces to distribute the work of serving traffic to more storage servers when needed or when the key space expands. Splits created to handle excess traffic are retained for around ~24 hours even if the traffic goes away. So if there are recurring traffic spikes, the splits are maintained and more splits are introduced whenever required. These mechanisms help Cloud Firestore databases to autoscale under increasing traffic load or database size. However, there are some limitations to be aware of as explained below.
Splitting storage and load takes time, and ramping up traffic too fast may cause high latency or deadline exceeded errors, commonly referred to as hotspots , while the service adjusts. The best practice is to distribute operations across the key range, while ramping up traffic on a collection in a database with 500 operations per second. After this gradual ramp up, increase the traffic by up to 50% every five minutes. This process is called the 500/50/5 rule and positions the database to optimally scale to meet your workload.
Though splits are created automatically with increasing load, Cloud Firestore can split a key range only until it's serving a single document using a dedicated set of replicated storage servers. As a result, high and sustained volumes of concurrent operations on a single document may lead to a hotspot on that document. If you encounter sustained high latencies on a single document, you should consider modifying your data model to split or replicate the data across multiple documents.
Contention errors happen when multiple operations try to read and/or write the same document simultaneously.
Another special case of hotspotting happens when a sequentially increasing/decreasing key is used as the document ID in Cloud Firestore , and there is a considerably high number of operations per second. Creating more splits doesn't help here since the surge of traffic simply moves to the newly created split. Since Cloud Firestore automatically indexes all fields in the document by default, such moving hotspots may also be created on the index space for a document field that contains a sequentially increasing/decreasing value like a timestamp.
Note that by following the practices outlined above, Cloud Firestore can scale to serve arbitrarily large workloads without you having to adjust any configuration.
Поиск неисправностей
Cloud Firestore provides the Key Visualizer as a diagnostic tool designed to analyze usage patterns and troubleshoot hotspotting issues.
Что дальше?
- Read about more best practices
- Learn about real-time queries at scale
Read this document to make informed decisions on architecting your applications for high performance and reliability. This document includes advanced Cloud Firestore topics. If you're just starting out with Cloud Firestore , see the quickstart guide instead.
Cloud Firestore is a flexible, scalable database for mobile device, web, and server development from Firebase and Google Cloud . It's very easy to get started with Cloud Firestore and write rich and powerful applications.
To make sure that your applications continue to perform well as your database size and traffic increase, it helps to understand the mechanics of reads and writes in the Cloud Firestore backend. You must also understand the interaction of your read and writes with the storage layer and the underlying constraints that may affect performance.
See the following sections for best practices before architecting your application.
Understand the high level components
The following diagram shows the high level components involved in a Cloud Firestore API request.

Cloud Firestore SDK and client libraries
Cloud Firestore supports SDKs and client libraries for different platforms. While an app can make direct HTTP and RPC calls to the Cloud Firestore API, the client libraries provide a layer of abstraction to simplify API usage and implement best practices. They may also provide additional features such as offline access, caches, and so on.
Google Front End (GFE)
This is an infrastructure service common to all Google cloud services. The GFE accepts incoming requests and forwards them to the relevant Google service ( Cloud Firestore service in this context). It also provides other important functionalities, including protection against Denial of Service attacks.
Cloud Firestore service
The Cloud Firestore service performs checks on the API request, which includes authentication, authorization, quota checks, and security rules, and also manages transactions. This Cloud Firestore service includes a storage client that interacts with the storage layer for the data reads and writes.
Cloud Firestore storage layer
The Cloud Firestore storage layer is responsible for storing both the data and metadata, and the associated database features provided by Cloud Firestore . The following sections describe how data is organized in the Cloud Firestore storage layer and how the system scales. Learning about how data is organized can help you design a scalable data model and better understand the best practices in Cloud Firestore .
Key Ranges and Splits
Cloud Firestore is a NoSQL, document-oriented database. You store data in documents , which are organized in hierarchies of collections . The collection hierarchy and document ID are translated to a single key for each document. Documents are logically stored and ordered lexicographically by this single key. We use the term key range to refer to a lexicographically contiguous range of keys.
A typical Cloud Firestore database is too large to fit on a single physical machine. There are also scenarios where the workload on the data is too heavy for one machine to handle. To handle large workloads, Cloud Firestore partitions the data into separate pieces that can be stored on and served from multiple machines or storage servers . These partitions are made on the database tables in blocks of key ranges called splits.
Синхронная репликация
It is important to note that the database is always being replicated automatically and synchronously. The splits of data have replicas in different zones to keep them available even when a zone becomes inaccessible. Consistent replication to the different copies of the split is managed by the Paxos algorithm for consensus. One replica of each split is elected to act as the Paxos leader, which is responsible for handling writes to that split. The synchronous replication gives you the ability to always be able to read the latest version of data from Cloud Firestore .
The overall result of this is a scalable and highly available system that provides low latencies for both reads and writes, irrespective of heavy workloads and at very large scale.
Структура данных
Cloud Firestore is a schemaless document database. However, internally it lays out the data primarily in two relational database-style tables in its storage layer as follows:
- Documents table: Documents are stored in this table.
- Indexes table: Index entries that make it possible to get results efficiently and sorted by index value are stored in this table.
The following diagram shows how the tables for a Cloud Firestore database might look like with the splits. The splits are replicated in three different zones and each split has an assigned Paxos leader.

Single Region versus Multi-Region
When you create a database, you must select a region or multi-region .
A single regional location is a specific geographic location, like us-west1 . The splits of data of a Cloud Firestore database have replicas in different zones within the selected region, as explained earlier.
A multi-region location consists of a defined set of regions where replicas of the database are stored. In a multi-region deployment of Cloud Firestore , two of the regions have full replicas of the entire data in the database. A third region has a witness replica that does not maintain a full set of data, but participates in replication. By replicating the data between multiple regions, data is available to be written and read even with the loss of an entire region.
For more information about the locations of a region, see Cloud Firestore locations .

Understand life of a write in Cloud Firestore
A Cloud Firestore client can write data by creating, updating, or deleting a single document. A write to a single document requires updating both the document and its associated index entries atomically in the storage layer. Cloud Firestore also supports atomic operations consisting of multiple reads and/or writes to one or more documents.
For all kinds of writes, Cloud Firestore provides the ACID properties (atomicity, consistency, isolation, and durability) of relational databases. Cloud Firestore also provides serializability , which means that all transactions appear as if executed in a serial order.
High-level steps in a write transaction
When the Cloud Firestore client issues a write or commits a transaction, using any of the methods mentioned earlier, internally this is executed as a database read-write transaction in the storage layer. The transaction enables Cloud Firestore to provide the ACID properties mentioned earlier.
As the first step of a transaction, Cloud Firestore reads the existing document, and determines the mutations to be made to the data in the Documents table.
This also includes making necessary updates to the Indexes table as follows:
- Fields that are being added to the documents need corresponding inserts in the Indexes table.
- Fields that are being removed from the documents need corresponding deletes in the Indexes table.
- Fields that are being modified in the documents, need both deletes (for old values) and inserts (for new values) in the Indexes table.
To calculate the mutations mentioned earlier, Cloud Firestore reads the indexing configuration for the database. The indexing configuration stores information about the indexes for a database. Cloud Firestore uses two types of indexes: single-field and composite. For a detailed understanding of the indexes created in Cloud Firestore , see Index types in Cloud Firestore .
Once the mutations are calculated, Cloud Firestore collects them inside a transaction and then commits it.
Understand a write transaction in the storage layer
As discussed earlier, a write in Cloud Firestore involves a read-write transaction in the storage layer. Depending on the layout of data, a write might involve one or more splits as seen in the data layout .
In the following diagram, the Cloud Firestore database has eight splits (marked 1-8) hosted on three different storage servers in a single zone, and each split is replicated in 3(or more) different zones. Each split has a Paxos leader, which might be in a different zone for different splits.
Cloud Firestore database split">
Consider a Cloud Firestore database that has the Restaurants collection as follows:

The Cloud Firestore client requests the following change to a document in the Restaurant collection by updating the value of the priceCategory field.

The following high-level steps describe what happens as part of the write:
- Create a read-write transaction.
- Read the
restaurant1document in theRestaurantscollection from the Documents table from the storage layer. - Read the indexes for the document from the Indexes table.
- Compute the mutations to be made to the data. In this case, there are five mutations:
- M1: Update the row for
restaurant1in the Documents table to reflect the change in value of thepriceCategoryfield. - M2 and M3: Delete the rows for the old value of
priceCategoryin the Indexes table for descending and ascending indexes. - M4 and M5: Insert the rows for the new value of
priceCategoryin the Indexes table for descending and ascending indexes.
- M1: Update the row for
- Commit these mutations.
The storage client in the Cloud Firestore service looks up the splits that owns the keys of the rows to be changed. Let's consider a case where Split 3 serves M1, and Split 6 serves M2-M5. There is a distributed transaction, involving all these splits as participants . The participant splits may also include any other split from which data was read earlier as part of the read-write transaction.
The following steps describe what happens as part of the commit:
- The storage client issues a commit. The commit contains the mutations M1-M5.
- Splits 3 and 6 are the participants in this transaction. One of the participants is chosen as the coordinator , such as Split 3. The job of the coordinator is to make sure the transaction either commits or aborts atomically across all participants.
- The leader replicas of these splits are responsible for work done by the participants and coordinators.
- Each participant and coordinator runs a Paxos algorithm with their respective replicas.
- The leader runs a Paxos algorithm with the replicas. Quorum is achieved if most of the replicas reply with an
ok to commitresponse to the leader. - Each participant then notifies the coordinator when they are prepared (first phase of two-phase commit). If any participant cannot commit the transaction, the whole transaction
aborts.
- The leader runs a Paxos algorithm with the replicas. Quorum is achieved if most of the replicas reply with an
- Once the coordinator knows all participants, including itself, are prepared, it communicates the
accepttransaction outcome to all the participants (second phase of two-phase commit). In this phase, each participant records the commit decision to stable storage and the transaction is committed. - The coordinator responds to the storage client in Cloud Firestore that the transaction has been committed. In parallel, the coordinator and all the participants apply the mutations to the data.

When the Cloud Firestore database is small, it may happen that a single split owns all the keys in the mutations M1-M5. In such a case, there is only one participant in the transaction and the two-phase commit mentioned earlier is not required, thus making the writes faster.
Writes in multi-region
In a multi-region deployment, the spread of replicas across regions increases availability, but comes with a performance cost. The communication between replicas in different regions takes longer round trip times. Hence, the baseline latency for Cloud Firestore operations is slightly more compared to single region deployments.
We configure the replicas in a way that leadership for splits always stays in the primary region. The primary region is the one from which traffic is incoming to the Cloud Firestore server. This decision of leadership reduces the round-trip delay in communication between the storage client in Cloud Firestore and the replica leader (or coordinator for multi-split transactions).
Each write in Cloud Firestore also involves some interaction with the real-time engine in Cloud Firestore . For more information about real-time queries, see Understand real-time queries at scale .
Understand the life of a read in Cloud Firestore
This section delves into standalone, non-realtime reads in Cloud Firestore . Internally, the Cloud Firestore server handles most of these queries in two major stages:
- A single range scan over the Indexes table
- Point lookups in the Documents table based on the result of the earlier scan
The data reads from the storage layer are internally done by using a database transaction to ensure consistent reads. However, unlike the transactions used for writes, these transactions do not take locks. Instead, they work by choosing a timestamp, then executing all reads at that timestamp. Since they do not acquire locks, they do not block concurrent read-write transactions. To execute this transaction, the storage client in Cloud Firestore specifies a timestamp bound, which tells the storage layer how to choose a read timestamp. The type of timestamp bound chosen by the storage client in Cloud Firestore is determined by the read options for the Read request.
Understand a read transaction in the storage layer
This section describes the types of reads and how they are processed in the storage layer in Cloud Firestore .
Strong reads
By default, Cloud Firestore reads are strongly consistent . This strong consistency means that a Cloud Firestore read returns the latest version of the data that reflects all writes that have been committed up until the start of the read.
Single Split read
The storage client in Cloud Firestore looks up the splits that own the keys of the rows to be read. Let's assume that it needs to do a read from Split 3 from the earlier section . The client sends the read request to the nearest replica to reduce round trip latency.
At this point, the following cases might happen depending on the chosen replica:
- Read request goes to a leader replica (Zone A).
- As the leader is always up-to-date, the read can proceed directly.
- Read request goes to a non-leader replica (such as, Zone B)
- Split 3 may know by its internal state that it has enough information to serve the read and the split does so.
- Split 3 is unsure if it has seen the latest data. It sends a message to the leader to ask for the timestamp of the last transaction it needs to apply to serve the read. Once that transaction is applied, the read can proceed.
Cloud Firestore then returns the response to its client.
Multi-split read
In the situation where the reads have to be done from multiple splits, the same mechanism happens across all the splits. Once the data has been returned from all the splits, the storage client in Cloud Firestore combines the results. Cloud Firestore then responds to its client with this data.
Заезженные книги
Strong reads are the default mode in Cloud Firestore . However, it comes at a cost of potential higher latency due to the communication that may be required with the leader. Often your Cloud Firestore application doesn't need to read the latest version of the data and the functionality works well with data that may be a few seconds stale.
In such a case, the client may opt to receive stale reads by using the read_time read options. In this case, reads are done as the data was at read_time , and the closest replica is highly likely to already have verified it has data at the specified read_time . For noticeably better performance, 15 seconds is a reasonable staleness value. Even for stale reads, rows yielded are consistent with each other.
Avoid hotspots
The splits in Cloud Firestore are automatically broken into smaller pieces to distribute the work of serving traffic to more storage servers when needed or when the key space expands. Splits created to handle excess traffic are retained for around ~24 hours even if the traffic goes away. So if there are recurring traffic spikes, the splits are maintained and more splits are introduced whenever required. These mechanisms help Cloud Firestore databases to autoscale under increasing traffic load or database size. However, there are some limitations to be aware of as explained below.
Splitting storage and load takes time, and ramping up traffic too fast may cause high latency or deadline exceeded errors, commonly referred to as hotspots , while the service adjusts. The best practice is to distribute operations across the key range, while ramping up traffic on a collection in a database with 500 operations per second. After this gradual ramp up, increase the traffic by up to 50% every five minutes. This process is called the 500/50/5 rule and positions the database to optimally scale to meet your workload.
Though splits are created automatically with increasing load, Cloud Firestore can split a key range only until it's serving a single document using a dedicated set of replicated storage servers. As a result, high and sustained volumes of concurrent operations on a single document may lead to a hotspot on that document. If you encounter sustained high latencies on a single document, you should consider modifying your data model to split or replicate the data across multiple documents.
Contention errors happen when multiple operations try to read and/or write the same document simultaneously.
Another special case of hotspotting happens when a sequentially increasing/decreasing key is used as the document ID in Cloud Firestore , and there is a considerably high number of operations per second. Creating more splits doesn't help here since the surge of traffic simply moves to the newly created split. Since Cloud Firestore automatically indexes all fields in the document by default, such moving hotspots may also be created on the index space for a document field that contains a sequentially increasing/decreasing value like a timestamp.
Note that by following the practices outlined above, Cloud Firestore can scale to serve arbitrarily large workloads without you having to adjust any configuration.
Поиск неисправностей
Cloud Firestore provides the Key Visualizer as a diagnostic tool designed to analyze usage patterns and troubleshoot hotspotting issues.
Что дальше?
- Read about more best practices
- Learn about real-time queries at scale