1. Обзор
Эта серия практических занятий (в удобном для вас темпе) призвана помочь разработчикам Google App Engine (Standard) модернизировать свои приложения, проведя их через ряд миграций. Большинство таких миграций связаны с отказом от встроенных сервисов оригинальной среды выполнения, поскольку среды выполнения следующего поколения более гибкие, предоставляя пользователям большее разнообразие вариантов сервисов. Другой способ модернизации приложения — это обновление до более новой версии, и именно этому посвящено данное практическое занятие.
Пользователи App Engine, обращающиеся к Datastore с помощью клиентских библиотек Cloud NDB или Cloud Datastore, могут сразу же перейти на другую платформу и не нуждаются в дальнейшей миграции. Однако Cloud Firestore представляет собой новейшее масштабируемое, высокодоступное хранилище данных NoSQL с функциями базы данных реального времени Firebase .
Если вы разработчик, который хочет использовать Firestore, чтобы воспользоваться его возможностями, или хотя бы заинтересован в изучении процесса миграции, то вы попали по адресу. В этом руководстве вы узнаете, как перенести приложение App Engine, использующее Cloud Datastore, в Cloud Firestore.
Вы узнаете, как
- Разберитесь в различиях между Datastore и Firestore.
- Переход с Cloud Datastore на Cloud Firestore
Что вам понадобится
- Проект Google Cloud Platform, в котором участвуют:
- Базовые навыки работы с Python.
- Практические навыки работы с распространенными командами Linux.
- Базовые знания разработки и развертывания приложений на платформе App Engine.
- Рекомендуется выполнить практическое задание из Модуля 3 , включая его адаптацию для Python 3, прежде чем приступать к этому заданию (Модуль 6).
- Рабочий пример приложения Cloud Datastore на Python 3 App Engine с модулем 3 .
Опрос
Как вы будете использовать этот практический урок?
2. Предыстория
В 2013 году хранилище данных App Engine стало самостоятельным продуктом — Google Cloud Datastore, — и теперь доступно разработчикам за пределами App Engine. В следующем году компания Firebase была приобретена Google. В то время она была известна своей базой данных реального времени.
В течение следующих нескольких лет команды Firebase и Cloud Datastore работали над интеграцией некоторых функций Firebase в Datastore. В результате в 2017 году было выпущено следующее поколение Cloud Datastore. Чтобы отразить унаследованные функции Firebase, оно было переименовано в Cloud Firestore .
Cloud Firestore стал стандартным механизмом хранения NoSQL-данных для проектов Google Cloud. Новые приложения могут использовать Cloud Firestore напрямую, в то время как существующие базы данных Datastore были преобразованы в Firestore и теперь работают в режиме «Firestore в Datastore» для сохранения совместимости с операциями Datastore. В результате приложения могут использовать Cloud Firestore только в одном из этих режимов, и после установки его нельзя изменить.
В настоящее время при создании новых проектов и выборе решения NoSQL пользователям предлагается выбрать либо режим Firestore в Datastore, либо режим Firestore в нативном режиме. После добавления сущностей Datastore пользователи не могут переключиться на Firestore, и аналогично, после выбора нативного режима Firestore они больше не могут вернуться к Datastore (или, точнее, к Firestore в режиме Datastore). Более подробную информацию можно найти на странице документации, посвященной выбору между режимом Cloud Firestore в Datastore и нативным режимом Firestore . Для миграции приложения в Firestore необходимо создать новый проект, экспортировать Datastore, а затем импортировать его в Firestore. Цель этого руководства — дать разработчикам представление о различиях между использованием Cloud Datastore и Cloud Firestore.
Мы не ожидаем, что пользователи будут выполнять эту миграцию , поэтому она является необязательной. Хотя использование Cloud Firestore в собственном виде имеет очевидные преимущества, такие как аутентификация клиента, интеграция с правилами Firebase и, конечно же, база данных Firebase в реальном времени, этапы миграции являются «неудобными»:
- Вам необходимо использовать другой проект, отличный от проекта вашего текущего приложения.
- В проекте, где приложение добавило сущности Datastore, переключение на Firestore в нативном режиме невозможно.
- Аналогичным образом, проект, в котором выбран Firestore в нативном режиме, не может вернуться к использованию Firestore в режиме хранилища данных.
- Не существует инструмента миграции, который мог бы передавать данные из одного проекта в другой.
- Некоторые важные функции Datastore, включая пространства имен и более высокую пропускную способность записи (>10 тыс. записей в секунду), недоступны в Firestore.
- Инструменты экспорта и импорта являются «примитивными» и работают по принципу «всё или ничего».
- Если ваше приложение содержит много сущностей из Datastore, экспорт и импорт в Firestore может занять много часов.
- В течение этого времени ваше приложение/сервис не сможет записывать/обновлять данные.
- Миграционные мероприятия учитываются в рамках обычного использования ресурсов; возможно, вам стоит распределить их (по возможности, по суточным квотам), чтобы минимизировать затраты.
- Поскольку ваш новый сервис работает в другом проекте, вам потребуется время для распространения обновлений DNS.
- Datastore и Firestore имеют схожие, но разные модели данных, поэтому для миграции потребуется обновить принцип работы приложения/сервиса.
- Запросы к родительским элементам из Datastore теперь являются запросами к коллекциям Firestore (по умолчанию).
- Запросы широкого типа из хранилища данных — это запросы к группам коллекций Firestore.
- Индексы и обработка данных различаются и т.д.
Учитывая все вышесказанное, если у вас есть достаточно простое приложение, которое вы планируете перенести, вы готовитесь к имитации такой миграции или просто хотите узнать больше о Datastore и Firestore, то, пожалуйста, продолжайте!
Пользователи Python 2: Этот необязательный практический пример по миграции представлен только для Python 3, однако, поскольку Cloud Firestore также поддерживает версию 2.x, пользователи могут интерполировать различия в использовании. Например, записи Firestore используют строки Unicode (вместо строк байтов), поэтому для строковых литералов Python 2 требуется ведущий индикатор u'' , то есть функция store_visit() в версии 2.x будет выглядеть следующим образом:
def store_visit(remote_addr, user_agent):
doc_ref = fs_client.collection(u'Visit')
doc_ref.add({
u'timestamp': datetime.now(),
u'visitor': u'{}: {}'.format(remote_addr, user_agent),
})
В остальном, клиентская библиотека должна работать аналогично. Единственный другой момент, который следует учитывать, заключается в том, что разработка библиотеки Cloud Firestore версии 2.x "заморожена", поэтому все больше и больше новых функций будут доступны только в клиентской библиотеке Firestore версии 3.x.
Для продолжения миграции выполните следующие основные шаги, описанные в этом руководстве:
- Подготовка/Настройка
- Добавить библиотеку Cloud Firestore
- Обновите файлы приложения
3. Подготовка/Предварительные работы
Прежде чем приступить к основной части урока, давайте настроим наш проект, получим код, а затем развернем базовое приложение, чтобы убедиться, что мы начали с работающего кода.
1. Настройка проекта
Мы рекомендуем использовать тот же проект, что и для выполнения практического задания модуля 3. В качестве альтернативы вы можете создать совершенно новый проект или использовать уже существующий. Убедитесь, что у проекта есть активный платежный аккаунт и включена поддержка App Engine (приложения).
2. Получите базовый образец приложения.
Одно из предварительных условий для выполнения этого практического задания — наличие работающего примера приложения из Модуля 3. Если у вас его нет, пройдите руководство по Модулю 3 (ссылка выше), прежде чем переходить к следующему шагу. В противном случае, если вы уже знакомы с его содержанием, вы можете просто начать, скачав код Модуля 3 ниже.
Независимо от того, используете ли вы свой или наш код, мы НАЧНЕМ с кода Модуля 3. Этот практический урок по Модулю 6 шаг за шагом проведет вас через каждый этап, и по завершении он должен выглядеть как код в КОНЦЕ. (Этот урок доступен только для Python 3.)
- НАЧАЛО: Репозиторий модуля 3
- ЗАВЕРШЕНИЕ: Репозиторий модуля 6
- Весь репозиторий (клонировать или скачать ZIP-архив)
Структура каталога файлов Модуля 3 (ваших или наших) должна выглядеть следующим образом:
$ ls
README.md main.py templates
app.yaml requirements.txt
3. (Повторное) развертывание приложения модуля 3.
Осталось выполнить следующие подготовительные шаги:
- При необходимости ознакомьтесь с инструментом командной строки
gcloud. - (При необходимости) повторно разверните код Модуля 3 в App Engine.
После успешного выполнения этих шагов и подтверждения работоспособности системы, мы перейдем к следующему этапу этого руководства, начиная с конфигурационных файлов.
Требования к Python 2
- Убедитесь, что
app.yaml(по-прежнему) содержит ссылки на сторонние пакеты:grpcioиsetuptools. - Убедитесь, что
appengine_config.pyпо-прежнему используетpkg_resourcesиgoogle.appengine.ext.vendorдля указания приложению на ресурсы сторонних разработчиков. - В следующем разделе, при обновлении файла
requirements.txt, необходимо использоватьgoogle-cloud-firestore==1.9.0поскольку это последняя версия клиентской библиотеки Python Firestore, совместимая с версией 2.x.- Если в вашем
requirements.txtесть запись дляgoogle-cloud-core, оставьте её как есть. - Удалите
libи переустановите её с помощьюpip install -t lib -r requirements.txt.`.
- Если в вашем
4. Обновите конфигурационные файлы (добавьте библиотеку Cloud Firestore).
После настройки следующими шагами являются обновление конфигурации, а затем и файлов приложения. В первом случае единственное изменение конфигурации — это небольшая замена пакетов в файле requirements.txt , поэтому давайте сделаем это сейчас.
Замените строку google-cloud-datastore на google-cloud-firestore в requirements.txt , чтобы получилось следующее:
Flask==1.1.2
google-cloud-firestore==2.0.2
Мы рекомендуем использовать последние версии каждой библиотеки; указанные выше номера версий являются актуальными на момент написания этого текста. Код в папке репозитория FINISH обновляется чаще и может содержать более новую версию.
Никаких других изменений в конфигурации не производилось, поэтому файлы app.yaml и templates/index.html остаются без изменений.
5. Обновите файлы приложения.
Приложение состоит всего из одного файла — main.py , поэтому все изменения в этом разделе затрагивают только этот файл.
1. Импорт
Переход на другой способ импорта пакетов — это незначительное изменение, заключающееся в замене datastore на firestore :
- ДО:
from google.cloud import datastore
- ПОСЛЕ:
from google.cloud import firestore
2. Доступ к Firestore
После инициализации Flask создайте клиент Firestore. Внесите аналогичные изменения, но для инициализации клиента:
- ДО:
app = Flask(__name__)
ds_client = datastore.Client()
- ПОСЛЕ:
app = Flask(__name__)
fs_client = firestore.Client()
Выполнив миграцию с Cloud NDB на Cloud Datastore, вы уже проделали основную работу по переходу на Cloud Firestore. В Datastore вы создаете записи данных в виде сущностей, состоящих из общих свойств, и группируете их по ключам . Записи данных в Firestore представляют собой документы, состоящие из пар ключ-значение и сгруппированные в коллекции . Миграция с Datastore требует учета этих различий, поскольку они проявятся как при создании записей данных, так и при выполнении запросов к ним. Результаты могут различаться в зависимости от сложности вашего кода для Datastore.
В Datastore запросы выполняются на основе типа сущности, а также критериев фильтрации и сортировки . В Firestore запросы к данным аналогичны. Рассмотрим простой пример, предполагая следующие значения запроса, клиентов ( ds_client или fs_client соответственно) и импорты:
from datetime import datetime
from firestore.Query import DESCENDING
OCT1 = datetime(2020, 10, 1)
LIMIT = 10
Для Datastore выполним запрос к десяти самым последним записям Visit датированным позже 1 октября 2020 года, в порядке убывания:
query = ds_client.query(kind='Visit')
query.add_filter('timestamp', '>=', datetime(2020, 10, 1))
query.order = ['-timestamp']
return query.fetch(limit=LIMIT)
То же самое я делаю для Firestore из коллекции Visit :
query = fs_client.collection('Visit')
query.where('timestamp', '>=', datetime(2020, 10, 1))
query.order_by('timestamp', direction=DESCENDING)
return query.limit(LIMIT).stream()
Пример запроса к приложению проще (без условия "WHERE"). Для повторения, вот код Cloud Datastore:
- ДО:
def store_visit(remote_addr, user_agent):
entity = datastore.Entity(key=ds_client.key('Visit'))
entity.update({
'timestamp': datetime.now(),
'visitor': '{}: {}'.format(remote_addr, user_agent),
})
ds_client.put(entity)
def fetch_visits(limit):
query = ds_client.query(kind='Visit')
query.order = ['-timestamp']
return query.fetch(limit=limit)
При переходе на Firestore создание новых документов будет аналогично созданию сущностей, а запросы — как показано ранее.
- ПОСЛЕ:
def store_visit(remote_addr, user_agent):
doc_ref = fs_client.collection('Visit')
doc_ref.add({
'timestamp': datetime.now(),
'visitor': '{}: {}'.format(remote_addr, user_agent),
})
def fetch_visits(limit):
visits_ref = fs_client.collection('Visit')
visits = (v.to_dict() for v in visits_ref.order_by('timestamp',
direction=firestore.Query.DESCENDING).limit(limit).stream())
return visits
Основная функция root() остается неизменной, как и файл шаблона index.html . Дважды проверьте изменения, сохраните, разверните и проверьте.
6. Подведение итогов/Завершение
Развертывание приложения
Переразверните приложение с помощью gcloud app deploy и убедитесь, что оно работает. Теперь ваш код должен соответствовать коду из репозитория модуля 6 (или версии 2.x, если вы предпочитаете именно её).
Если вы начали этот цикл, не выполнив ни одного из предыдущих практических заданий, само приложение не изменится; оно регистрирует все посещения главной веб-страницы ( / ) и выглядит так после того, как вы достаточное количество раз посетите сайт:

Поздравляем с завершением этой необязательной миграции в Модуле 6. Вероятно, это одна из последних, если не последняя, миграция, которую вы можете осуществить в отношении хранилища данных App Engine. В качестве альтернативы вы можете рассмотреть контейнеризацию вашего приложения для Cloud Run, если вы еще этого не сделали (см. Модули 4 и 5, ссылки на практические задания ниже).
Необязательно: Уборка
Как насчет того, чтобы навести порядок и избежать выставления счетов до тех пор, пока вы не будете готовы перейти к следующему этапу миграции на CodeLab? Как опытные разработчики, вы, вероятно, уже знакомы с информацией о ценах App Engine .
(Необязательно): Отключить приложение
Если вы ещё не готовы перейти к следующему уроку, отключите своё приложение, чтобы избежать списания средств. Когда вы будете готовы перейти к следующему практическому занятию, вы можете снова включить его. Пока ваше приложение отключено, оно не будет получать трафик, за который могли бы взиматься плата, однако с вас могут взиматься дополнительные платежи за использование Firestore , если оно превысит бесплатную квоту , поэтому удалите достаточное количество приложений, чтобы оно не превышало этот лимит.
С другой стороны, если вы не собираетесь продолжать миграции и хотите полностью удалить все, вы можете закрыть свой проект .
Следующие шаги
Помимо этого руководства, вы можете рассмотреть несколько других практических заданий по модулям миграции:
- Модуль 7: Очереди задач App Engine Push (необходим, если вы используете очереди задач [push])
- Добавляет задачи из очереди
taskqueueApp Engine в приложение Модуля 1. - В модуле 8 осуществляется подготовка пользователей к миграции в облако.
- Добавляет задачи из очереди
- Модуль 4: Миграция в облако. Запуск с помощью Docker.
- Создайте контейнер для запуска вашего приложения в Cloud Run с помощью Docker.
- Эта миграция позволит вам остаться на Python 2.
- Модуль 5: Миграция в облако. Запуск с помощью Cloud Buildpacks.
- Создайте контейнер для запуска вашего приложения в Cloud Run с помощью Cloud Buildpacks.
- Вам не нужно ничего знать о Docker, контейнерах или
Dockerfile. - Для корректной работы требуется, чтобы ваше приложение уже было переведено на Python 3 (Buildpacks не поддерживает Python 2).
7. Дополнительные ресурсы
Проблемы/обратная связь по модулю миграции App Engine на Codelabs
Если вы обнаружите какие-либо проблемы в этом практическом задании, пожалуйста, сначала найдите свою проблему, прежде чем сообщать о ней. Ссылки для поиска и создания новых проблем:
Миграционные ресурсы
Ссылки на папки репозитория для Модуля 3 (НАЧАЛО) и Модуля 6 (ЗАВЕРШЕНИЕ) можно найти в таблице ниже. К ним также можно получить доступ из репозитория для всех миграций App Engine , который можно клонировать или загрузить в виде ZIP-файла.
Кодлаб | Python 2 | Python 3 |
( код ) | ||
Модуль 6 | (н/д) |
Ресурсы App Engine
Ниже приведены дополнительные ресурсы, касающиеся данной конкретной миграции:
- Справочник по Python Cloud Datastore и Cloud Firestore
- Переход на Python 3 и среду выполнения GAE нового поколения
- Общий