Catch up on highlights from Firebase at Google I/O 2023. Learn more

Procedure consigliate per Cloud Firestore

Utilizza le best practice elencate qui come riferimento rapido durante la creazione di un'applicazione che utilizza Cloud Firestore.

Posizione della banca dati

Quando crei l'istanza del database, seleziona la posizione del database più vicina agli utenti e alle risorse di calcolo. Gli hop di rete di vasta portata sono più soggetti a errori e aumentano la latenza delle query.

Per massimizzare la disponibilità e la durabilità della tua applicazione, seleziona una posizione in più aree geografiche e colloca le risorse di calcolo critiche in almeno due aree geografiche.

Seleziona una località regionale per costi inferiori, per una minore latenza di scrittura se la tua applicazione è sensibile alla latenza o per la co-ubicazione con altre risorse GCP .

ID documento

  • Evita gli ID documento . e ..
  • Evita di utilizzare / barre negli ID documento.
  • Non utilizzare ID documento che aumentano in modo monotono come:

    • Customer1 , Customer2 , Customer3 , ...
    • Product 1 , Product 2 , Product 3 , ...

    Tali ID sequenziali possono portare a hotspot che influiscono sulla latenza.

Nomi di campo

  • Evita i seguenti caratteri nei nomi dei campi perché richiedono caratteri di escape aggiuntivi:

    • . periodo
    • [ parentesi sinistra
    • ] parentesi quadra destra
    • * asterisco
    • ` apice inverso

Indici

  • Evitare di utilizzare troppi indici. Un numero eccessivo di indici può aumentare la latenza di scrittura e aumentare i costi di archiviazione per le voci di indice.

  • Tieni presente che l'indicizzazione di campi con valori crescenti in modo monotono, come i timestamp, può portare a hotspot che influiscono sulla latenza per le applicazioni con velocità di lettura e scrittura elevate.

Esenzioni dall'indice

Per la maggior parte delle app, puoi fare affidamento sull'indicizzazione automatica e su eventuali collegamenti ai messaggi di errore per gestire i tuoi indici. Tuttavia, potresti voler aggiungere esenzioni a campo singolo nei seguenti casi:

Caso Descrizione
Grandi campi stringa

Se disponi di un campo stringa che contiene spesso valori stringa lunghi che non utilizzi per le query, puoi ridurre i costi di archiviazione esentando il campo dall'indicizzazione.

Velocità di scrittura elevate in una raccolta contenente documenti con valori sequenziali

Se indicizzi un campo che aumenta o diminuisce in sequenza tra i documenti in una raccolta, come un timestamp, la velocità massima di scrittura nella raccolta è di 500 scritture al secondo. Se non esegui query in base al campo con valori sequenziali, puoi esentare il campo dall'indicizzazione per ignorare questo limite.

In un caso d'uso IoT con un'elevata velocità di scrittura, ad esempio, una raccolta contenente documenti con un campo timestamp potrebbe avvicinarsi al limite di 500 scritture al secondo.

Campi TTL

Se utilizzi i criteri TTL (time-to-live) , tieni presente che il campo TTL deve essere un timestamp. L'indicizzazione sui campi TTL è abilitata per impostazione predefinita e può influire sulle prestazioni a tassi di traffico più elevati. Come best practice, aggiungi esenzioni a campo singolo per i tuoi campi TTL.

Matrice di grandi dimensioni o campi mappa

I campi matrice o mappa di grandi dimensioni possono avvicinarsi al limite di 40.000 voci di indice per documento. Se non stai eseguendo una query in base a un campo di matrice o mappa di grandi dimensioni, dovresti esentarlo dall'indicizzazione.

Operazioni di lettura e scrittura

  • La velocità massima esatta con cui un'app può aggiornare un singolo documento dipende fortemente dal carico di lavoro. Per ulteriori informazioni, vedere Aggiornamenti a un singolo documento .

  • Utilizzare le chiamate asincrone, ove disponibili, anziché le chiamate sincrone. Le chiamate asincrone riducono al minimo l'impatto della latenza. Ad esempio, si consideri un'applicazione che necessita del risultato di una ricerca di documenti e dei risultati di una query prima di eseguire il rendering di una risposta. Se la ricerca e la query non hanno una dipendenza dati, non è necessario attendere in modo sincrono il completamento della ricerca prima di avviare la query.

  • Non utilizzare offset. Invece, usa i cursori . L'utilizzo di un offset evita solo di restituire i documenti saltati all'applicazione, ma questi documenti vengono comunque recuperati internamente. I documenti ignorati influiscono sulla latenza della query e all'applicazione vengono fatturate le operazioni di lettura necessarie per recuperarli.

Tentativi di transazione

Gli SDK e le librerie client di Cloud Firestore ritentano automaticamente le transazioni non riuscite per gestire gli errori temporanei. Se la tua applicazione accede a Cloud Firestore direttamente tramite le API REST o RPC anziché tramite un SDK, la tua applicazione dovrebbe implementare tentativi di transazione per aumentare l'affidabilità.

Aggiornamenti in tempo reale

Per le best practice relative agli aggiornamenti in tempo reale, vedere Comprendere le query in tempo reale su larga scala .

Progettare per la scala

Le procedure consigliate seguenti descrivono come evitare situazioni che creano problemi di contesa.

Aggiornamenti a un singolo documento

Mentre progetti la tua app, considera quanto velocemente la tua app aggiorna i singoli documenti. Il modo migliore per caratterizzare le prestazioni del tuo carico di lavoro è eseguire il test del carico. La velocità massima esatta con cui un'app può aggiornare un singolo documento dipende fortemente dal carico di lavoro. I fattori includono la velocità di scrittura, la contesa tra le richieste e il numero di indici interessati.

Un'operazione di scrittura di un documento aggiorna il documento e gli eventuali indici associati e Cloud Firestore applica l'operazione di scrittura in modo sincrono a un quorum di repliche. A velocità di scrittura sufficientemente elevate, il database inizierà a riscontrare contesa, latenza più elevata o altri errori.

Elevate velocità di lettura, scrittura ed eliminazione su un intervallo di documenti ristretto

Evita velocità di lettura o scrittura elevate per chiudere lessicograficamente i documenti, altrimenti la tua applicazione riscontrerà errori di contesa. Questo problema è noto come hotspotting e la tua applicazione può riscontrare hotspotting se esegue una delle seguenti operazioni:

  • Crea nuovi documenti a una velocità molto elevata e alloca i propri ID in modo monotono.

    Cloud Firestore alloca gli ID documento utilizzando un algoritmo di dispersione. Non dovresti riscontrare hotspotting durante le scritture se crei nuovi documenti utilizzando ID documento automatici.

  • Crea nuovi documenti a una velocità elevata in una raccolta con pochi documenti.

  • Crea nuovi documenti con un campo in aumento monotono, come un timestamp, a una velocità molto elevata.

  • Elimina i documenti in una raccolta a una velocità elevata.

  • Scrive nel database a una velocità molto elevata senza aumentare gradualmente il traffico.

Evita di saltare i dati cancellati

Evita le query che ignorano i dati eliminati di recente. Una query potrebbe dover ignorare un numero elevato di voci di indice se i primi risultati della query sono stati eliminati di recente.

Un esempio di un carico di lavoro che potrebbe dover ignorare molti dati eliminati è quello che tenta di trovare gli elementi di lavoro in coda meno recenti. La query potrebbe essere simile a:

docs = db.collection('WorkItems').order_by('created').limit(100)
delete_batch = db.batch()
for doc in docs.stream():
  finish_work(doc)
  delete_batch.delete(doc.reference)
delete_batch.commit()

Ogni volta che questa query viene eseguita, esegue la scansione delle voci di indice per il campo created su tutti i documenti eliminati di recente. Questo rallenta le query.

Per migliorare le prestazioni, utilizza il metodo start_at per trovare il punto di partenza migliore. Per esempio:

completed_items = db.collection('CompletionStats').document('all stats').get()
docs = db.collection('WorkItems').start_at(
    {'created': completed_items.get('last_completed')}).order_by(
        'created').limit(100)
delete_batch = db.batch()
last_completed = None
for doc in docs.stream():
  finish_work(doc)
  delete_batch.delete(doc.reference)
  last_completed = doc.get('created')

if last_completed:
  delete_batch.update(completed_items.reference,
                      {'last_completed': last_completed})
  delete_batch.commit()

NOTA: l'esempio precedente utilizza un campo in aumento monotono che è un anti-pattern per velocità di scrittura elevate.

Aumento del traffico

Dovresti aumentare gradualmente il traffico verso nuove raccolte o chiudere lessicograficamente i documenti per dare a Cloud Firestore il tempo sufficiente per preparare i documenti per l'aumento del traffico. Ti consigliamo di iniziare con un massimo di 500 operazioni al secondo per una nuova raccolta e quindi aumentare il traffico del 50% ogni 5 minuti. Allo stesso modo puoi aumentare il tuo traffico di scrittura, ma tieni a mente i limiti standard di Cloud Firestore . Assicurati che le operazioni siano distribuite in modo relativamente uniforme in tutta la gamma di tasti. Questa è chiamata la regola "500/50/5".

Migrazione del traffico verso una nuova raccolta

L'aumento graduale è particolarmente importante se esegui la migrazione del traffico delle app da una raccolta a un'altra. Un modo semplice per gestire questa migrazione è leggere dalla vecchia raccolta e, se il documento non esiste, leggere dalla nuova raccolta. Tuttavia, ciò potrebbe causare un improvviso aumento del traffico per chiudere lessicograficamente i documenti della nuova raccolta. Cloud Firestore potrebbe non essere in grado di preparare in modo efficiente la nuova raccolta per l'aumento del traffico, soprattutto quando contiene pochi documenti.

Un problema simile può verificarsi se si modificano gli ID documento di molti documenti all'interno della stessa raccolta.

La migliore strategia per la migrazione del traffico a una nuova raccolta dipende dal modello di dati. Di seguito è riportato un esempio di strategia nota come letture parallele . Dovrai determinare se questa strategia è efficace o meno per i tuoi dati e una considerazione importante sarà l'impatto sui costi delle operazioni parallele durante la migrazione.

Letture parallele

Per implementare letture parallele durante la migrazione del traffico a una nuova raccolta, leggi prima dalla vecchia raccolta. Se manca il documento, leggi dalla nuova raccolta. Un alto tasso di letture di documenti inesistenti può portare a hotspotting, quindi assicurati di aumentare gradualmente il carico della nuova raccolta. Una strategia migliore consiste nel copiare il vecchio documento nella nuova raccolta, quindi eliminare il vecchio documento. Aumenta gradualmente le letture parallele per assicurarti che Cloud Firestore sia in grado di gestire il traffico verso la nuova raccolta.

Una possibile strategia per aumentare gradualmente le letture o le scritture in una nuova raccolta consiste nell'usare un hash deterministico dell'ID utente per selezionare una percentuale casuale di utenti che tentano di scrivere nuovi documenti. Assicurati che il risultato dell'hash dell'ID utente non sia distorto dalla tua funzione o dal comportamento dell'utente.

Nel frattempo, esegui un lavoro batch che copia tutti i tuoi dati dai vecchi documenti alla nuova raccolta. Il tuo processo batch dovrebbe evitare le scritture su ID documento sequenziali per evitare hotspot. Al termine del processo batch, è possibile leggere solo dalla nuova raccolta.

Un perfezionamento di questa strategia consiste nel migrare piccoli batch di utenti alla volta. Aggiungi un campo al documento dell'utente che tenga traccia dello stato di migrazione di quell'utente. Seleziona un batch di utenti di cui eseguire la migrazione in base a un hash dell'ID utente. Utilizzare un processo batch per migrare i documenti per quel batch di utenti e utilizzare le letture parallele per gli utenti nel mezzo della migrazione.

Si noti che non è possibile eseguire facilmente il rollback a meno che non si eseguano doppie scritture sia della vecchia che della nuova entità durante la fase di migrazione. Ciò aumenterebbe i costi sostenuti per Cloud Firestore.

Impedire l'accesso non autorizzato

Impedisci le operazioni non autorizzate sul tuo database con le regole di sicurezza di Cloud Firestore. Ad esempio, l'utilizzo delle regole potrebbe evitare uno scenario in cui un utente malintenzionato scarica ripetutamente l'intero database.

Ulteriori informazioni sull'utilizzo delle regole di sicurezza di Cloud Firestore .