Modulo 6: Migrazione da Cloud Datastore a Cloud Firestore

1. Panoramica

Questa serie di codelab (tutorial pratici e self-service) mira ad aiutare gli sviluppatori di Google App Engine (standard) a modernizzare le loro app, guidandoli attraverso una serie di migrazioni. La maggior parte di queste migrazioni comporta l'abbandono dei servizi in bundle del runtime originali, in quanto i runtime di nuova generazione sono più flessibili e offrono agli utenti una maggiore varietà di opzioni di servizi. Un altro modo per modernizzare un'app include l'upgrade a un prodotto più recente ed è l'oggetto di questo codelab.

Gli utenti di App Engine che accedono a Datastore con le librerie client di Cloud NDB o Cloud Datastore sono pronti e non devono eseguire ulteriori migrazioni. Tuttavia, Cloud Firestore rappresenta il datastore NoSQL più recente, scalabile e ad alta disponibilità con funzionalità del database in tempo reale Firebase.

Sei nel posto giusto se sei uno sviluppatore che si sente in dovere di utilizzare Firestore per sfruttare le sue funzionalità o che ha almeno un interesse sufficiente per esplorare ciò che comporta la migrazione. Questo tutorial insegna come eseguire la migrazione di un'app App Engine a Cloud Firestore utilizzando Cloud Datastore.

Imparerai a

  • Riconoscere le differenze tra Datastore e Firestore
  • Esegui la migrazione da Cloud Datastore a Cloud Firestore

Che cosa ti serve

Sondaggio

Come utilizzerai questo codelab?

Da leggere solo Leggilo e completa gli esercizi

2. Sfondo

Datastore di App Engine è diventato un prodotto a sé stante nel 2013, Google Cloud Datastore ed è ora accessibile agli sviluppatori al di fuori di App Engine. L'anno successivo, Firebase è stato acquisito da Google. All'epoca era nota per i suoi database in tempo reale.

Nei prossimi anni, i team di Firebase e Cloud Datastore hanno lavorato all'integrazione di alcune delle funzionalità di Firebase in Datastore. Di conseguenza, nel 2017, è stata rilasciata la nuova generazione di Cloud Datastore. Per riflettere l'ereditarietà di alcune funzionalità di Firebase, il servizio è stato rinominato Cloud Firestore.

Cloud Firestore è diventato il meccanismo di archiviazione NoSQL predefinito per i progetti Google Cloud. Le nuove app possono utilizzare Cloud Firestore in modo nativo, mentre i database Datastore esistenti sono stati convertiti in Firestore in background e ora funzionano come "Firestore in modalità Datastore" per preservare la compatibilità con le operazioni di Datastore. Di conseguenza, le applicazioni possono eseguire Cloud Firestore solo in una di queste modalità e, una volta impostata, non può essere modificata.

Al momento, quando gli utenti creano nuovi progetti e selezionano una soluzione NoSQL, viene chiesto di selezionare Firestore in modalità Datastore o Firestore in modalità nativa. Una volta che gli utenti hanno aggiunto le entità Datastore, non possono passare a Firestore e, allo stesso modo, una volta selezionata la modalità nativa di Firestore, non possono più tornare a Datastore (o meglio a Firestore in modalità Datastore). Per ulteriori dettagli, leggi la pagina relativa alla scelta tra Cloud Firestore in modalità Datastore o la modalità nativa di Firestore nella documentazione. Per eseguire la migrazione di un'app in Firestore, è necessario creare un nuovo progetto, Datastore esportato e poi importato in Firestore. Lo scopo di questo tutorial è fornire agli sviluppatori un'idea delle differenze tra l'utilizzo di Cloud Datastore e Cloud Firestore.

Questa migrazione non è prevista dagli utenti, per questo motivo si tratta di una migrazione facoltativa. Sebbene ci siano evidenti vantaggi nell'uso nativo di Cloud Firestore come l'autenticazione del client, l'integrazione delle regole di Firebase e, naturalmente, il database in tempo reale Firebase, i passaggi della migrazione sono "scomodi":

  • Devi usare un progetto diverso da quello dell'app attuale.
  • Un progetto in cui un'app ha aggiunto entità Datastore non può essere passato a Firestore in modalità nativa
  • Allo stesso modo, un progetto che ha selezionato Firestore in modalità nativa non può ripristinare Firestore in modalità Datastore.
  • Non esiste uno strumento di migrazione in grado di trasmettere flussi di dati da un progetto a un altro.
  • Alcune funzionalità critiche di Datastore, inclusi gli spazi dei nomi e una velocità effettiva di scrittura più elevata (>10.000/s), non sono disponibili in Firestore.
  • Gli strumenti di esportazione e importazione sono "primitivi" e "tutto o niente" diversi scenari.
    • Se l'app ha molte entità Datastore, l'esportazione e l'importazione in Firestore possono richiedere molte ore.
    • Durante questo periodo, l'applicazione o il servizio non sarà in grado di scrivere/aggiornare i dati.
    • Le attività di migrazione contano ai fini dell'utilizzo normale; potresti voler distribuirla (tra le quote giornaliere, se possibile) per ridurre al minimo i costi.
    • Poiché il nuovo servizio viene eseguito in un progetto diverso, avrai bisogno di una finestra per la propagazione degli aggiornamenti DNS.
  • Datastore e Firestore hanno modelli dei dati simili ma diversi, pertanto la migrazione richiede l'aggiornamento del funzionamento dell'app/del servizio
    • Le query predecessore di Datastore sono ora query di raccolta di Firestore (l'impostazione predefinita)
    • Le query di tipo ampio di Datastore sono query del gruppo di raccolte di Firestore
    • Gli indici e la gestione sono diversi ecc.

Detto questo, se hai un'app piuttosto semplice da prendere in considerazione per la migrazione, se ti stai preparando per simulare una migrazione di questo tipo o se sei semplicemente qui per scoprire di più su Datastore e Firestore, continua!

Utenti di Python 2: questo codelab di migrazione facoltativo è presentato solo in Python 3. Tuttavia, poiché Cloud Firestore supporta anche 2.x, gli utenti possono interpolare le differenze di utilizzo. Un esempio è che i record Firestore utilizzano stringhe Unicode (anziché stringhe di byte), quindi è necessario un indicatore iniziale u'' per i valori letterali stringa Python 2, il che significa che una funzione store_visit() 2.x sarà simile a questa:

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

A parte questo, la libreria client dovrebbe funzionare in modo simile. L'unico altro problema da considerare è che la libreria Cloud Firestore 2.x è "bloccata" Per quanto riguarda lo sviluppo, le funzionalità sempre più/più recenti saranno disponibili solo nella libreria client Firestore 3.x.

Se procedi con la migrazione, ecco i passaggi principali di questo tutorial:

  1. Configurazione/pre-lavoro
  2. Aggiungi la libreria Cloud Firestore
  3. Aggiorna i file dell'applicazione

3. Configurazione/pre-lavoro

Prima di proseguire con la parte principale del tutorial, impostiamo il progetto, recuperiamo il codice ed eseguiamo il deployment dell'app di base in modo da sapere di aver iniziato con il codice funzionante.

1. Configura il progetto

Ti consigliamo di riutilizzare lo stesso progetto che hai utilizzato per completare il codelab del Modulo 3. In alternativa, puoi creare un nuovo progetto o riutilizzare un altro progetto esistente. Assicurati che il progetto abbia un account di fatturazione attivo e che App Engine (app) sia abilitato.

2. Ottieni app di esempio di riferimento

Uno dei prerequisiti di questo codelab è avere un'app di esempio funzionante del Modulo 3. Se non ne hai uno, completa il tutorial del modulo 3 (link qui sopra) prima di proseguire qui. Altrimenti, se ne hai già familiarità con i contenuti, puoi iniziare a cercare il codice del Modulo 3 riportato di seguito.

Che tu usi il tuo o il nostro, il codice del Modulo 3 è quello in cui INIZIAMO. Questo codelab del modulo 6 illustra ogni passaggio e, una volta completato, dovrebbe assomigliare al codice nel punto FINISH. Questo tutorial è disponibile solo per Python 3.

La directory dei file del modulo 3 (tuoi o nostri) dovrebbe avere il seguente aspetto:

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

3. (Ri)Esegui il deployment dell'app Modulo 3

I passaggi preliminari rimanenti da eseguire ora:

  1. Acquisisci familiarità con lo strumento a riga di comando gcloud (se necessario)
  2. (Ri)eseguire il deployment del codice del Modulo 3 in App Engine (se necessario).

Dopo aver eseguito correttamente questi passaggi e aver confermato che è operativo, proseguiremo con questo tutorial, iniziando con i file di configurazione.

Requisiti per Python 2

  • Assicurati che app.yaml (ancora) faccia riferimento ai pacchetti di terze parti in bundle: grpcio e setuptools.
  • Assicurati che appengine_config.py utilizzi ancora pkg_resources e google.appengine.ext.vendor per indirizzare l'app alle risorse di terze parti.
  • Nella sezione successiva che aggiorna requirements.txt, devi utilizzare google-cloud-firestore==1.9.0, che è la versione finale compatibile con 2.x della libreria client Python Firestore.
    • Se il tuo requirements.txt ha una voce per google-cloud-core, lasciala invariata.
    • Elimina lib e reinstalla con pip install -t lib -r requirements.txt.

4. Aggiorna i file di configurazione (aggiungi la libreria Cloud Firestore)

Dopo l'impostazione, i passaggi successivi necessari sono l'aggiornamento della configurazione seguito dai file dell'applicazione. Nel primo caso, l'unica modifica alla configurazione è un piccolo scambio di pacchetti nel file requirements.txt, quindi lo facciamo ora.

Sostituisci la riga google-cloud-datastore con google-cloud-firestore in requirements.txt in modo che abbia il seguente aspetto:

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

Ti consigliamo di utilizzare le versioni più recenti di ogni libreria. i numeri di versione sopra riportati sono le più recenti al momento della stesura del presente documento. Il codice nella cartella del repository FINISH viene aggiornato con maggiore frequenza e potrebbe avere una versione più recente.

Non sono state apportate altre modifiche alla configurazione, quindi app.yaml e templates/index.html rimangono invariati.

5. Aggiorna i file dell'applicazione

Esiste un solo file dell'applicazione, main.py, quindi tutte le modifiche apportate in questa sezione vengono applicate soltanto a quel file.

1. Importazioni

Il cambio di importazione del pacchetto è una piccola modifica da datastore a firestore:

  • PRIMA:
from google.cloud import datastore
  • DOPO:
from google.cloud import firestore

2. Accesso a Firestore

Dopo aver inizializzato Flask, crea il tuo client Firestore. Apporta una modifica simile a quella riportata sopra ma per l'inizializzazione del client:

  • PRIMA:
app = Flask(__name__)
ds_client = datastore.Client()
  • DOPO:
app = Flask(__name__)
fs_client = firestore.Client()

Eseguendo la migrazione da Cloud NDB a Cloud Datastore, hai già svolto le attività più impegnative per arrivare a Cloud Firestore. Con Datastore, crei record di dati sotto forma di entità costituite da proprietà comuni e li raggruppi per chiavi. I record di dati in Firestore sono Documenti, composti da coppie chiave-valore e raggruppati insieme in Raccolte. La migrazione da Datastore richiede di tenere conto di queste differenze perché si materializzano durante la creazione dei record di dati e l'esecuzione delle query. I risultati possono variare a seconda della complessità del codice Datastore.

Per Datastore, devi eseguire query basate sul tipo di entità, oltre a criteri di filtro e ordinamento. Per Firestore, l'esecuzione di query sui dati è simile. Vediamo un breve esempio, supponendo che questi valori di query, i client (ds_client o fs_client, rispettivamente) e le importazioni:

from datetime import datetime
from firestore.Query import DESCENDING

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

Per Datastore, eseguiamo una query per le dieci entità Visit più recenti del 1° ottobre 2020 in ordine decrescente:

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

Fai lo stesso per Firestore, dalla raccolta 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 query sull'app di esempio è più semplice (nessuna clausola "WHERE"). Ecco il codice di Cloud Datastore:

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

Eseguendo la migrazione a Firestore, scoprirai la creazione di nuovi documenti simili alle entità e le query come mostrato in precedenza.

  • DOPO:
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 funzione principale root() rimane la stessa del file del modello index.html. Controlla le modifiche, salva, esegui il deployment e verifica.

6. Riepilogo/Pulizia

Esegui il deployment di un'applicazione

Esegui di nuovo il deployment dell'app con gcloud app deploy e verifica che funzioni. Ora il codice dovrebbe corrispondere a quello presente nel repository del Modulo 6 (o una versione 2.x, se questa era la tua preferenza).

Se hai seguito questa serie senza aver eseguito nessuno dei codelab precedenti, l'app in sé non cambierà: vengono registrate tutte le visite alla pagina web principale (/) e si presenta come questa una volta che hai visitato il sito un numero sufficiente di volte:

app visitme

Congratulazioni per aver completato la migrazione facoltativa del Modulo 6. Questa è probabilmente una delle migrazioni, se non le ultime, che puoi eseguire per quanto riguarda lo spazio di archiviazione dei dati di App Engine. Una migrazione alternativa che puoi prendere in considerazione è containerizzare la tua app per Cloud Run, se non l'hai già fatto (vedi i Moduli 4 e 5, i codelab di cui trovi i link di seguito).

(Facoltativo) Eseguire la pulizia

Che ne dici di eseguire la pulizia per evitare di ricevere addebiti finché non decidi di passare al codelab di migrazione successivo? In qualità di sviluppatori esistenti, probabilmente sei già al passo con le informazioni sui prezzi di App Engine.

(Facoltativo) Disattiva l'app

Se non vuoi ancora passare al prossimo tutorial, disattiva la tua app per evitare che ti vengano addebitati dei costi. Quando vuoi passare al codelab successivo, puoi riabilitarlo. Mentre la tua app è disabilitata, non riceverà traffico che comporta addebiti, ma un'altra cosa che ti può essere fatturata è l'utilizzo di Firestore se supera la quota senza costi, quindi eliminane un numero sufficiente per rientrare nel limite.

Se invece non intendi continuare con le migrazioni e vuoi eliminare tutto il tutto, puoi chiudere il progetto.

Passaggi successivi

Oltre a questo tutorial, ci sono molti altri codelab per i moduli di migrazione che puoi prendere in considerazione:

  • Modulo 7: Code di attività push di App Engine (obbligatorie se utilizzi le code di attività [push])
    • Aggiunge attività push di taskqueue di App Engine all'app del modulo 1
    • Prepara gli utenti alla migrazione a Cloud Tasks nel modulo 8
  • Modulo 4: Esegui la migrazione a Cloud Run con Docker
    • Containerizza la tua app per eseguirla su Cloud Run con Docker
    • Questa migrazione ti consente di rimanere su Python 2.
  • Modulo 5: Esegui la migrazione a Cloud Run con Cloud Buildpacks
    • Containerizza la tua app per eseguirla su Cloud Run con Cloud Buildpacks
    • Non devi conoscere Docker, container o Dockerfile.
    • Richiede che l'app abbia già eseguito la migrazione a Python 3 (Buildpacks non supporta Python 2)

7. Risorse aggiuntive

Problemi/feedback dei codelab per i moduli di migrazione di App Engine

Se riscontri problemi con questo codelab, cercali prima di procedere con l'invio. Link per eseguire ricerche e creare nuovi problemi:

Risorse di migrazione

I link alle cartelle repository per il modulo 3 (START) e il modulo 6 (FINISH) sono disponibili nella tabella seguente. Sono inoltre accessibili dal repository per tutte le migrazioni di App Engine che puoi clonare o scaricare un file ZIP.

Codelab

Python 2

Python 3

Module 3

(codice)

codice

Modulo 6

(n/d)

codice

Risorse App Engine

Di seguito sono riportate ulteriori risorse relative a questa specifica migrazione: