Module 6: Migrer de Cloud Datastore vers Cloud Firestore

1. Présentation

Cette série d'ateliers de programmation (tutoriels pratiques et d'auto-formation) vise à aider les développeurs Google App Engine (standard) à moderniser leurs applications en les guidant lors d'une série de migrations. La majorité de ces migrations impliquent l'abandon des services groupés d'exécution d'origine, car les environnements d'exécution de nouvelle génération sont plus flexibles et offrent aux utilisateurs une plus grande variété d'options de services. Un autre moyen de moderniser une application consiste à passer à un produit plus récent. C'est l'objet de cet atelier de programmation.

Les utilisateurs App Engine qui accèdent à Datastore à l'aide des bibliothèques clientes Cloud NDB ou Cloud Datastore sont prêts à l'emploi et n'ont pas besoin d'effectuer de migration supplémentaire. Cependant, Cloud Firestore représente le dernier datastore NoSQL, évolutif et hautement disponible, avec les fonctionnalités de la base de données en temps réel Firebase.

Vous êtes au bon endroit si vous êtes un développeur et que vous pensez être obligé d'utiliser Firestore pour exploiter ses fonctionnalités ou si vous êtes au moins assez intéressé pour explorer les implications de la migration. Ce tutoriel vous explique comment migrer une application App Engine utilisant Cloud Datastore vers Cloud Firestore.

Vous apprendrez à effectuer les tâches suivantes :

  • Identifier les différences entre Datastore et Firestore
  • Effectuer une migration de Cloud Datastore vers Cloud Firestore

Prérequis

Enquête

Comment allez-vous utiliser cet atelier de programmation ?

<ph type="x-smartling-placeholder"></ph> Je vous invite à le lire uniquement Je vais le lire et effectuer les exercices
.

2. Contexte

Datastore d'App Engine est devenu son propre produit en 2013, Google Cloud Datastore, et est désormais accessible aux développeurs en dehors d'App Engine. L'année suivante, Google a racheté Firebase. À l'époque, il était connu pour sa base de données en temps réel.

Au cours des années suivantes, les équipes Firebase et Cloud Datastore ont travaillé sur l'intégration de certaines fonctionnalités de Firebase dans Datastore. Par conséquent, en 2017, la nouvelle génération de Cloud Datastore a été lancée. Afin de refléter l'héritage de certaines fonctionnalités de Firebase, la solution a été rebaptisée Cloud Firestore.

Cloud Firestore est devenu le mécanisme de stockage NoSQL par défaut pour les projets Google Cloud. Les nouvelles applications peuvent utiliser Cloud Firestore de manière native, tandis que les bases de données Datastore existantes ont été converties en Firestore en arrière-plan et fonctionnent désormais sous le nom "Firestore en mode Datastore". afin de préserver la compatibilité avec les opérations Datastore. Par conséquent, les applications ne peuvent faire fonctionner Cloud Firestore que dans l'un de ces modes. Une fois défini, il ne peut plus être modifié.

Actuellement, lorsque les utilisateurs créent des projets et sélectionnent une solution NoSQL, ils sont invités à sélectionner Firestore en mode Datastore ou Firestore en mode natif. Une fois que les utilisateurs ont ajouté des entités Datastore, ils ne peuvent pas passer à Firestore. De même, une fois le mode natif de Firestore sélectionné, ils ne peuvent plus revenir à Datastore (ou plutôt à Firestore en mode Datastore). Pour en savoir plus, consultez la page Choisir entre Cloud Firestore en mode Datastore et le mode Firestore natif dans la documentation. Pour migrer une application vers Firestore, vous devez créer un projet, puis l'exporter et l'importer dans Firestore. L'objectif de ce tutoriel est de donner aux développeurs une idée des différences entre l'utilisation de Cloud Datastore et de Cloud Firestore.

Les utilisateurs ne sont pas censés effectuer cette migration. C'est pourquoi il s'agit d'une migration facultative. L'utilisation native de Cloud Firestore présente des avantages évidents, tels que l'authentification client, l'intégration des règles Firebase et, bien sûr, la base de données en temps réel Firebase. Cependant, les étapes de migration sont "inconvénients" :

  • Vous devez utiliser un projet différent de celui de votre application actuelle.
  • Un projet dans lequel une application a ajouté des entités Datastore ne peut pas passer à Firestore en mode natif
  • De même, un projet ayant sélectionné Firestore en mode natif ne peut pas revenir à Firestore en mode Datastore.
  • Aucun outil de migration ne peut diffuser des données d'un projet à un autre.
  • Certaines fonctionnalités essentielles de Datastore, comme les espaces de noms et un débit en écriture supérieur (> 10 000/s), ne sont pas disponibles dans Firestore.
  • Les outils d'exportation et d'importation sont "primitifs" et "tout ou rien" différents scénarios.
    • Si votre application comporte de nombreuses entités Datastore, l'exportation, puis l'importation dans Firestore peuvent prendre plusieurs heures.
    • Pendant cette période, votre application/service ne pourra pas écrire/mettre à jour de données.
    • Les activités de migration sont comptabilisées dans l'utilisation normale. vous pouvez les répartir (sur des quotas quotidiens si possible) afin de réduire les coûts.
    • Étant donné que votre nouveau service s'exécute dans un projet différent, vous aurez besoin d'une fenêtre pour que les mises à jour DNS se propagent.
  • Datastore et Firestore ont des modèles de données similaires, mais différents. La migration nécessite donc de mettre à jour le fonctionnement de l'application ou du service.
    • Les requêtes ascendantes de Datastore sont désormais des requêtes de collection Firestore (par défaut).
    • Les requêtes en requête large provenant de Datastore sont des requêtes de groupe de collections Firestore
    • Les index et la gestion sont différents, etc.

Cela dit, si vous avez une application assez simple à envisager pour la migration, si vous vous préparez à simuler une telle migration, ou si vous souhaitez simplement en savoir plus sur Datastore et Firestore, n'hésitez pas à continuer.

Utilisateurs de Python 2:cet atelier de programmation facultatif sur la migration n'est présenté que dans Python 3. Toutefois, étant donné que Cloud Firestore est également compatible avec la version 2.x, les utilisateurs peuvent interpoler les différences d'utilisation. Par exemple, les enregistrements Firestore utilisent des chaînes Unicode (au lieu de chaînes d'octets). Un indicateur de début u'' est donc nécessaire pour les littéraux de chaîne Python 2, ce qui signifie qu'une fonction store_visit() 2.x se présente comme suit:

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),
    })

En dehors de cela, la bibliothèque cliente devrait fonctionner de la même manière. Le seul autre problème à prendre en compte est le fait que la bibliothèque Cloud Firestore 2.x est "figée" en ce qui concerne le développement, des fonctionnalités de plus en plus récentes/de plus en plus récentes ne seront disponibles que dans la bibliothèque cliente Firestore 3.x.

Voici les principales étapes de cette migration:

  1. Configuration/Préparation
  2. Ajouter une bibliothèque Cloud Firestore
  3. Mettre à jour les fichiers de l'application

3. Configuration/Préparation

Avant de passer à la partie principale de ce tutoriel, nous allons configurer notre projet, obtenir le code et déployer l'application de base pour nous assurer de bien utiliser du code fonctionnel.

1. Configurer le projet

Nous vous recommandons de réutiliser le projet que vous avez utilisé pour l'atelier de programmation du module 3. Vous pouvez également créer un projet ou réutiliser un autre projet existant. Assurez-vous que le projet dispose d'un compte de facturation actif et que App Engine (app) est activé.

2. Obtenir un exemple d'application de référence

L'une des conditions préalables à cet atelier de programmation est de disposer d'une application exemple du module 3 qui fonctionne. Si vous n'en avez pas, suivez le tutoriel du module 3 (lien ci-dessus) avant de poursuivre. Si vous connaissez déjà son contenu, vous pouvez commencer par saisir le code du module 3 ci-dessous.

Que vous utilisiez le vôtre ou le nôtre, nous allons commencer par le code du module 3. Cet atelier de programmation du module 6 vous guide à travers chaque étape. Une fois l'atelier terminé, il doit ressembler à du code au point TERMINÉ. (Ce tutoriel n'est disponible que pour Python 3.)

Le répertoire des fichiers du module 3 (les vôtres ou les nôtres) devrait se présenter comme suit:

$ ls
README.md               main.py                 templates
app.yaml                requirements.txt

3. (Re)Déployer l'application du module 3

Étapes préliminaires restantes :

  1. Familiarisez-vous avec l'outil de ligne de commande gcloud (si nécessaire).
  2. (Re)déployer le code du module 3 sur App Engine (si nécessaire)

Une fois que vous avez exécuté ces étapes et vérifié le bon fonctionnement du code, nous pouvons passer à la suite de ce tutoriel en commençant par les fichiers de configuration.

Configuration requise pour Python 2

  • Assurez-vous que app.yaml fait (toujours) référence aux packages groupés tiers: grpcio et setuptools.
  • Assurez-vous que appengine_config.py utilise toujours pkg_resources et google.appengine.ext.vendor pour diriger l'application vers des ressources tierces.
  • Dans la section suivante pour mettre à jour requirements.txt, vous devez utiliser google-cloud-firestore==1.9.0, car il s'agit de la version finale compatible 2.x de la bibliothèque cliente Python Firestore.
    • Si votre requirements.txt comporte une entrée pour google-cloud-core, laissez-la telle quelle.
    • Supprimez lib et réinstallez-le avec pip install -t lib -r requirements.txt.

4. Mettre à jour les fichiers de configuration (ajouter la bibliothèque Cloud Firestore)

Au-delà de la configuration, vous devez ensuite mettre à jour la configuration, puis les fichiers de l'application. Dans le premier cas, la seule modification de configuration est un échange mineur de package dans votre fichier requirements.txt. Nous allons donc le faire maintenant.

Remplacez la ligne google-cloud-datastore par google-cloud-firestore dans requirements.txt pour qu'elle se présente comme suit:

Flask==1.1.2
google-cloud-firestore==2.0.2

Nous vous recommandons d'utiliser les dernières versions de chaque bibliothèque. Les numéros de version ci-dessus sont les plus récents au moment de la rédaction de ce document. Le code du dossier du dépôt FINISH est mis à jour plus fréquemment et peut avoir une version plus récente.

Aucune autre modification de configuration n'a été apportée. app.yaml et templates/index.html restent donc tels quels.

5. Mettre à jour les fichiers de l'application

Il n'y a qu'un fichier d'application : main.py. Par conséquent, toutes les modifications de la présente section s'appliquent uniquement à ce fichier.

1. Importations

Le changement de l'importation de package est une modification mineure de datastore à firestore:

  • AVANT :
from google.cloud import datastore
  • APRÈS :
from google.cloud import firestore

2. Accès à Firestore

Après avoir initialisé Flask, créez votre client Firestore. Effectuez une modification semblable à celle ci-dessus, mais pour l'initialisation du client:

  • AVANT :
app = Flask(__name__)
ds_client = datastore.Client()
  • APRÈS :
app = Flask(__name__)
fs_client = firestore.Client()

En effectuant la migration de Cloud NDB vers Cloud Datastore, vous avez déjà fait le gros du travail pour accéder à Cloud Firestore. Avec Datastore, vous créez des enregistrements de données sous la forme d'entités composées de propriétés communes et les regroupez par clés. Dans Firestore, les enregistrements de données sont des documents constitués de paires clé/valeur regroupées dans des collections. La migration depuis Datastore nécessite de réfléchir à ces différences, car elles se matérialiseront lorsque vous créerez des enregistrements de données et effectuerez des requêtes les concernant. Vos résultats peuvent varier en fonction de la complexité de votre code Datastore.

Pour Datastore, vous effectuez des requêtes basées sur le type d'entité avec des critères de filtrage et de tri. Pour Firestore, le processus d'interrogation des données est semblable. Examinons un exemple rapide en supposant que les valeurs de requête, les clients (ds_client ou fs_client, respectivement) et les importations sont les suivants:

from datetime import datetime
from firestore.Query import DESCENDING

OCT1 = datetime(2020, 10, 1)
LIMIT = 10

Pour Datastore, nous allons exécuter une requête sur les 10 entités Visit les plus récentes, antérieures au 1er octobre 2020, par ordre décroissant:

query = ds_client.query(kind='Visit')
query.add_filter('timestamp', '>=', datetime(2020, 10, 1))
query.order = ['-timestamp']
return query.fetch(limit=LIMIT)

Faire de même pour Firestore, à partir de la collection Visit:

query = fs_client.collection('Visit')
query.where('timestamp', '>=', datetime(2020, 10, 1))
query.order_by('timestamp', direction=DESCENDING)
return query.limit(LIMIT).stream()

La requête de l'application exemple est plus simple (sans clause "WHERE"). Pour rappel, voici le code Cloud Datastore:

  • AVANT :
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)

Lors de la migration vers Firestore, vous allez créer des documents semblables aux entités et exécuter les requêtes comme indiqué précédemment.

  • APRÈS :
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

La fonction principale root() reste identique à celle du fichier de modèle index.html. Vérifiez vos modifications, enregistrez-les, déployez-les et vérifiez-les.

6. Résumé/Nettoyage

Déployer l'application

Redéployez votre application avec gcloud app deploy et confirmez qu'elle fonctionne correctement. Votre code doit maintenant correspondre à ce qui se trouve dans le dépôt du module 6 (ou une version 2.x, si vous préférez cette version).

Si vous avez consulté cette série sans suivre les ateliers de programmation précédents, l'application elle-même ne change pas. Elle enregistre toutes les visites sur la page Web principale (/) et ressemble à ceci une fois que vous avez consulté le site suffisamment de fois :

Application Visitme

Félicitations ! Vous avez terminé cette migration facultative du module 6. Il s'agit probablement d'une migration, si ce n'est la dernière, que vous pouvez effectuer dans le domaine du stockage de données App Engine. Si vous ne l'avez pas déjà fait, vous pouvez également envisager de conteneuriser votre application pour Cloud Run (consultez les modules 4 et 5, dont les liens sont fournis ci-dessous).

Facultatif : Effectuer un nettoyage

Que diriez-vous d'un bon nettoyage pour éviter que des frais vous soient facturés tant que vous n'êtes pas prêt à passer à l'atelier de programmation suivant sur la migration ? En tant que développeur existant, vous connaissez probablement déjà les informations de tarification d'App Engine.

Facultatif : Désactiver l'application

Si vous n'êtes pas encore prêt à passer au tutoriel suivant, désactivez votre application pour éviter les frais. Lorsque vous serez prêt à passer au prochain atelier de programmation, vous pourrez le réactiver. Lorsque votre application est désactivée, aucun trafic n'entraîne de frais. Cependant, vous pouvez également être facturé pour votre utilisation de Firestore si elle dépasse le quota sans frais. Vous devez donc supprimer suffisamment de données pour passer sous cette limite.

En revanche, si vous ne souhaitez pas poursuivre vos migrations et souhaitez supprimer tous les éléments, vous pouvez arrêter le projet.

Étapes suivantes

En plus de ce tutoriel, vous pouvez suivre d'autres ateliers de programmation concernant la migration:

  • Module 7 : files d'attente d'envoi de tâches App Engine (obligatoire si vous utilisez des files d'attente de tâches d'envoi de tâches [push])
    • Ajoutez des tâches push taskqueue App Engine à l'application du module 1.
    • Préparez les utilisateurs à migrer vers Cloud Tasks dans le module 8.
  • Module 4 : Migrer vers Cloud Run avec Docker
    • Conteneurisez votre application pour l'exécuter sur Cloud Run avec Docker.
    • Cette migration vous permet de rester sur Python 2.
  • Module 5 : Migrer vers Cloud Run avec les packs de création Cloud
    • Conteneurisez votre application pour qu'elle s'exécute sur Cloud Run avec les packs de création Cloud.
    • Il n'est pas nécessaire de déjà connaître Docker, les conteneurs ou les Dockerfile.
    • Nécessite que votre application ait déjà été migrée vers Python 3 (les packs de création ne sont pas compatibles avec Python 2)

7. Ressources supplémentaires

Problèmes/commentaires concernant le module de migration App Engine en atelier de programmation

Si vous rencontrez des problèmes avec cet atelier de programmation, commencez par faire une recherche avant de les signaler. Liens vers la recherche et la création d'un signalement :

Ressources de migration

Le tableau ci-dessous contient des liens vers les dossiers de dépôt des modules 3 (START) et 6 (FINISH). Vous pouvez également y accéder depuis le dépôt pour toutes les migrations App Engine que vous pouvez cloner ou télécharger sous forme de fichier ZIP.

Atelier de programmation

Python 2

Python 3

Module 3

(code)

code

Module 6

(n/a)

code

Ressources App Engine

Vous trouverez ci-dessous d'autres ressources concernant cette migration spécifique :