Best practice per Cloud Firestore

Utilizza le best practice elencate qui come riferimento rapido quando crei un'applicazione che utilizza Cloud Firestore.

Località del database

Quando crei la tua istanza di database, seleziona il campo database località più vicina a utenti e risorse di computing. I hop di rete di ampio raggio 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ù regioni e posiziona le risorse di calcolo critiche in almeno due regioni.

Seleziona una località a livello di regione per ridurre i costi, per una minore latenza di scrittura se la tua applicazione è sensibile alla latenza o per la colocazione con altre risorse Google Cloud.

ID documenti

  • Evita gli ID documento . e ...
  • Evita di utilizzare / barre negli ID documento.
  • Non utilizzare ID documento che aumentano in modo monotonico, ad esempio:

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

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

Nomi campi

  • Evita i seguenti caratteri nei nomi dei campi perché richiedono un'interpretazione letterale aggiuntiva:

    • . punto
    • [ parentesi quadra aperta
    • ] parentesi quadra chiusa
    • * asterisco
    • ` accento grave

Indici

Riduci la latenza di scrittura

Il fattore principale che contribuisce alla latenza di scrittura è il fanout dell'indice. Le best practice per di riduzione del fanout dell'indice sono:

  • Imposta esenzioni dell'indice a livello di raccolta. Un'impostazione predefinita semplice è disattivare l'ordinamento decrescente e l'indice array. La rimozione dei valori indicizzati inutilizzati ridurrà anche i costi di archiviazione.

  • Riduci il numero di documenti in una transazione. Per scrivere un numero elevato di documenti, valuta la possibilità di utilizzare uno scrittore collettivo anziché il batch atomico scrittore.

Esenzioni dell'indice

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

Richiesta Descrizione
Campi stringa grandi

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

Frequenze di scrittura elevate in una raccolta contenente documenti con valori sequenziali

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

In un caso d'uso IoT con un'elevata frequenza 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 nei campi TTL è attivata per impostazione predefinita e può influire sul rendimento a tassi di traffico più elevati. Come best practice, aggiungi esenzioni a campo singolo per i campi TTL.

Array di grandi dimensioni o campi della mappa

I campi array o di mappa di grandi dimensioni possono avvicinarsi al limite di 40.000 voci di indice per documento. Se non stai eseguendo query sulla base di un array o di un campo di mappa di grandi dimensioni, devi esentarlo dall'indicizzazione.

Operazioni di lettura e scrittura

  • La frequenza massima esatta con cui un'app può aggiornare un singolo documento dipende molto dal carico di lavoro. Per ulteriori informazioni, consulta Aggiornamenti a un singolo documento.

  • Utilizza chiamate asincrone, se disponibili, anziché chiamate sincrone. Le chiamate asincrone riducono al minimo l'impatto della latenza. Ad esempio, considera un'applicazione che richiede il risultato di una ricerca di documenti e i risultati di una query prima per eseguire il rendering di una risposta. Se la ricerca e la query non hanno una dipendenza dai dati, non è necessario attendere in modo sincrono il completamento della ricerca prima di iniziare la query.

  • Non utilizzare gli offset. Utilizza invece cursori. L'utilizzo di un offset evita solo restituendo all'applicazione i documenti ignorati, ma questi documenti sono recuperate internamente. I documenti ignorati influiscono sulla latenza della query e alla tua applicazione vengono addebitate le operazioni di lettura necessarie per recuperarli.

Nuovi tentativi di transazione

Gli SDK e il client Cloud Firestore nuovo tentativo automatico delle librerie non riuscito delle transazioni per gestire errori temporanei. Se la tua applicazione accede a Cloud Firestore tramite le API REST o RPC direttamente invece che tramite un SDK, deve implementare i tentativi di transazione per aumentare l'affidabilità.

Aggiornamenti in tempo reale

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

Progettazione per la scalabilità

Le best practice riportate di seguito descrivono come evitare situazioni che possono creare problemi di contesa.

Aggiornamenti a un singolo documento

Durante la progettazione dell'app, valuta la velocità con cui l'app aggiorna i singoli documenti. Il modo migliore per caratterizzare le prestazioni del carico di lavoro è eseguire il carico test. La frequenza massima esatta con cui un'app può aggiornare un singolo documento dipende molto dal carico di lavoro. I fattori includono la frequenza di scrittura, il conflitto tra le richieste e il numero degli indici interessati.

Un'operazione di scrittura del 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. Se le velocità di scrittura sono sufficientemente elevate, il database inizierà quando si verificano conflitti, latenza più elevata o altri errori.

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

Evita frequenze di lettura o scrittura elevate per chiudere i documenti in ordine alfabetico, altrimenti la tua applicazione riscontrerà errori di contesa. Questo problema è noto come hotspotting e la tua applicazione può rilevare l'hotspot se esegue una delle le seguenti:

  • Crea nuovi documenti a una velocità molto elevata e assegna i propri ID in aumento in modo monotonico.

    Cloud Firestore assegna gli ID documento utilizzando un algoritmo di dispersione. Tu non dovrebbero riscontrare hotspot sulle scritture se crei nuovi documenti utilizzando gli ID documento automatici.

  • Crea nuovi documenti ad alta velocità in una raccolta con pochi documenti.

  • Crea nuovi documenti con un campo in aumento monotonico, come con una frequenza molto elevata.

  • Elimina i documenti di una raccolta a una frequenza elevata.

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

Evitare di saltare i dati eliminati

Evita query che ignorano i dati eliminati di recente. Una query potrebbe dover saltare un gran numero di voci dell'indice se i risultati iniziali della query sono stati eliminati di recente.

Un esempio di carico di lavoro che potrebbe dover saltare molti dati eliminati è quello che tenta di trovare gli elementi di lavoro in coda più vecchi. La query potrebbe avere il seguente aspetto:

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 viene eseguita questa query, vengono analizzate le voci dell'indice per il campo created in tutti i documenti eliminati di recente. Ciò rallenta le query.

Per migliorare il rendimento, utilizza il metodo start_at per trovare il punto di partenza migliore. Ad 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 riportato sopra utilizza un campo con valori in aumento monotonico, che è un anti-pattern per frequenze di scrittura elevate.

Aumento del traffico

Devi aumentare gradualmente il traffico verso nuove raccolte o meno chiudi i documenti per concedere a Cloud Firestore il tempo sufficiente per prepararsi documenti per un aumento del traffico. Ti consigliamo di iniziare con un massimo di 500 operazioni al secondo per una nuova raccolta e di aumentare il traffico del 50% ogni 5 minuti. Puoi aumentare in modo simile il traffico di scrittura, ma tieni presente i Limiti standard di Cloud Firestore. Assicurati che che le operazioni siano distribuite in modo relativamente uniforme nell'intervallo di chiavi. Questa è la regola "500/50/5".

Migrazione del traffico a una nuova raccolta

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

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

La strategia migliore per eseguire la migrazione del traffico a una nuova raccolta dipende dal tuo modello di dati. Di seguito è riportata una strategia di esempio nota come letture parallele. Dovrai determinare se questa strategia è efficace per i tuoi dati e un aspetto importante da considerare 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 dalla vecchia raccolta. Se il documento non è presente, leggilo dal nuova raccolta. Un tasso elevato di letture di documenti inesistenti può portare a hotspot, quindi assicurati di aumentare gradualmente il carico sulla nuova raccolta. Una strategia migliore è copiare il vecchio documento nella nuova raccolta e poi eliminarlo. Incrementare gradualmente le letture parallele per garantire Cloud Firestore può gestire il traffico verso la nuova raccolta.

Una possibile strategia per incrementare gradualmente le letture o le scritture in una nuova raccolta consiste nell'utilizzare un hash deterministico dell'ID utente per selezionare una percentuale casuale di dagli 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 job batch che copia tutti i dati dai vecchi documenti alla nuova raccolta. Il job batch deve evitare le scritture in ID documento sequenziali per evitare hotspot. Al termine del job batch, puoi leggere solo dalla nuova raccolta.

Un perfezionamento di questa strategia consiste nel eseguire la migrazione di piccoli batch di utenti alla volta. Aggiungi al documento utente un campo 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. Utilizza un job batch per eseguire la migrazione dei documenti per quel batch di utenti e le letture parallele per gli utenti nel mezzo della migrazione.

Tieni presente che non puoi eseguire facilmente il rollback se non esegui la doppia scrittura di entrambe e nuove entità durante la fase di migrazione. Ciò aumenterebbe i costi Cloud Firestore sostenuti.

Privacy

  • Evita di archiviare informazioni sensibili in un ID progetto Cloud. Un ID progetto cloud potrebbero essere conservati per tutta la durata del progetto.
  • Come best practice per la conformità dei dati, consigliamo di non archiviare dati informazioni nei nomi dei documenti e nei nomi dei campi dei documenti.

Impedire l'accesso non autorizzato

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

Scopri di più sull'utilizzo di Cloud Firestore Security Rules.