Best practice per Cloud Firestore

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

Posizione della banca dati

Quando crei l'istanza del database, seleziona la posizione del database più vicina ai tuoi 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 località multiregione e posiziona le risorse di elaborazione critiche in almeno due regioni.

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

  • Evitare gli ID dei documenti . E .. .
  • Evitare di utilizzare le barre / negli ID dei documenti.
  • Non utilizzare ID documento ad aumento monotono come:

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

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

Nomi dei campi

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

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

Indici

Riduci la latenza di scrittura

Il principale contributo alla latenza di scrittura è il fanout dell'indice. Le migliori pratiche per ridurre il fanout dell'indice sono:

  • Impostare le esenzioni dall'indice a livello di raccolta . Un'impostazione predefinita semplice è disabilitare l'indicizzazione discendente e di array. Anche la rimozione dei valori indicizzati inutilizzati ridurrà i costi di archiviazione .

  • Ridurre il numero di documenti in una transazione. Per scrivere un numero elevato di documenti, prendere in considerazione l'utilizzo di un bulk writer invece del atomic batch writer.

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 per campo singolo nei seguenti casi:

Caso Descrizione
Campi stringa di grandi dimensioni

Se disponi di un campo stringa che spesso contiene 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 di una raccolta, come un timestamp, la velocità di scrittura massima 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 aggirare 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 le policy 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 velocità di traffico più elevate. Come procedura consigliata, aggiungi esenzioni per campo singolo per i campi TTL.

Campi di matrice o mappa di grandi dimensioni

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

Operazioni di lettura e scrittura

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

  • Utilizzare chiamate asincrone, ove disponibili, anziché chiamate sincrone. Le chiamate asincrone riducono al minimo l'impatto della latenza. Si consideri, ad esempio, un'applicazione che necessita del risultato di una ricerca di documenti e dei risultati di una query prima di restituire 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 avviare la query.

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

Nuovi tentativi di transazione

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

Aggiornamenti in tempo reale

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

Progettare in scala

Le seguenti best practice descrivono come evitare situazioni che creano problemi di conflitto.

Aggiornamenti a un singolo documento

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

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

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

Evitare velocità di lettura o scrittura elevate per chiudere i documenti dal punto di vista lessicografico, altrimenti l'applicazione riscontrerà errori di conflitto. Questo problema è noto come hotspot e l'applicazione può riscontrare l'hotspot se esegue una delle seguenti operazioni:

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

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

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

  • Crea nuovi documenti con un campo che aumenta in modo 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 query che saltano i dati eliminati di recente. Potrebbe essere necessario ignorare un numero elevato di voci di indice in una query se i primi risultati della query sono stati eliminati di recente.

Un esempio di carico di lavoro che potrebbe dover ignorare molti dati eliminati è quello che tenta di trovare gli elementi di lavoro in coda più vecchi. 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 viene eseguita, questa query esegue la scansione delle voci di indice per il campo created su tutti i documenti eliminati di recente. Ciò rallenta le query.

Per migliorare le prestazioni, utilizza il metodo start_at per trovare il punto migliore da cui iniziare. 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 ad aumento monotono che è un anti-modello per velocità di scrittura elevate.

Traffico in aumento

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

Migrazione del traffico a una nuova raccolta

L'aumento graduale è particolarmente importante se si esegue 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 nella nuova raccolta. Cloud Firestore potrebbe non essere in grado di preparare in modo efficiente la nuova raccolta per un aumento del traffico, soprattutto quando contiene pochi documenti.

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

La migliore strategia per migrare il traffico verso 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 le letture parallele durante la migrazione del traffico a una nuova raccolta, leggi prima dalla vecchia raccolta. Se il documento manca, leggi dalla nuova raccolta. Un tasso elevato di letture di documenti inesistenti può portare all'hotspot, quindi assicurati di aumentare gradualmente il carico sulla nuova raccolta. Una strategia migliore è copiare il vecchio documento nella nuova raccolta, quindi eliminare il vecchio documento. Aumenta gradualmente le letture parallele per garantire che Cloud Firestore possa gestire il traffico verso la nuova raccolta.

Una possibile strategia per aumentare 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 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 lavoro batch dovrebbe evitare scritture su ID di documenti sequenziali per prevenire hotspot. Al termine del processo batch, puoi leggere solo dalla nuova raccolta.

Un perfezionamento di questa strategia consiste nella migrazione di piccoli gruppi di utenti alla volta. Aggiungi un campo al documento 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. Utilizza un processo batch per migrare i documenti per quel batch di utenti e utilizza letture parallele per gli utenti nel mezzo della migrazione.

Tieni presente che non puoi eseguire facilmente il rollback a meno che non effettui doppie scritture sia delle vecchie che delle nuove entità durante la fase di migrazione. Ciò aumenterebbe i costi sostenuti per Cloud Firestore.

Privacy

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

Impedire l'accesso non autorizzato

Previeni 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 .