Utilizza le best practice elencate qui come riferimento rapido quando crei un'applicazione che utilizza Cloud Firestore.
Località del database
Quando crei l'istanza di database, seleziona la posizione del database più vicina agli utenti e alle risorse di calcolo. Gli hop di rete ad 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 documento
- Evita gli ID documento
.
e..
. - Evita di utilizzare barre oblique
/
negli ID documento. Non utilizzare ID documento in aumento 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 ridurre il 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 non utilizzati riduce 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é lo scrittore batch atomico.
Esenzioni dall'indice
Per la maggior parte delle app, puoi fare affidamento sull'indicizzazione automatica e su eventuali link ai messaggi di errore per gestire gli indici. Tuttavia, ti consigliamo di aggiungere esenzioni per un singolo campo nei seguenti casi:
Richiesta | Descrizione |
---|---|
Campi di stringhe di grandi dimensioni | 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 modo sequenziale tra i documenti di una raccolta, ad esempio un timestamp, la frequenza di scrittura massima per la 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 una frequenza di scrittura elevata, 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 o campi mappa di grandi dimensioni | I campi di mappe o array di grandi dimensioni possono avvicinarsi al limite di 40.000 voci dell'indice per documento. Se non esegui query in base a un array o a un campo mappa di grandi dimensioni, devi esentarli 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 le chiamate asincrone, se disponibili, anziché le chiamate sincrone. Le chiamate asincrone riducono al minimo l'impatto della latenza. Ad esempio, considera un'applicazione che ha bisogno del risultato di una ricerca di documenti e dei risultati di una query prima di visualizzare 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 i cursori. L'utilizzo di un offset evita solo di restituire i documenti saltati alla tua applicazione, ma questi documenti vengono comunque recuperati 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 le librerie client Cloud Firestore tentano automaticamente di nuovo le transazioni non riuscite per gestire gli 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 Informazioni sulle query in tempo reale su larga scala.
Progettazione per la scalabilità
Le seguenti best practice descrivono come evitare situazioni che creano problemi di contesa.
Aggiornamenti a un singolo documento
Mentre progetti la tua app, considera la rapidità con cui l'app aggiorna i singoli documenti. Il modo migliore per caratterizzare le prestazioni del carico di lavoro è eseguire test di carico. 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, la concorrenza 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 conflitti, latenza più elevata o altri errori.
Alte frequenze di lettura, scrittura ed eliminazione in un intervallo ristretto di documenti
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ò verificarlo se esegue una delle seguenti operazioni:
Crea nuovi documenti a una frequenza elevata e assegna i propri ID monotonici crescenti.
Cloud Firestore alloca gli ID documento utilizzando un algoritmo a dispersione. Non dovresti riscontrare hotspot sulle scritture se crei nuovi documenti utilizzando ID documento automatici.
Crea nuovi documenti ad alta velocità in una raccolta con pochi documenti.
Crea nuovi documenti con un campo che aumenta in modo monotonico, ad esempio un timestamp, con una frequenza molto elevata.
Elimina i documenti di una raccolta ad alta frequenza.
Scrive nel database a una velocità molto elevata senza aumentare gradualmente il traffico.
Evita 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 questa query viene eseguita, analizza le voci di indice per il campo created
nei documenti eliminati di recente. Ciò rallenta le query.
Per migliorare le prestazioni, 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 le frequenze di scrittura elevate.
Aumento del traffico
Devi aumentare gradualmente il traffico verso le nuove raccolte o i documenti correlati per dare a Cloud Firestore tempo sufficiente per preparare i documenti all'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 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 raccolta all'altra. 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'importante considerazione 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 raccolta precedente. Se il documento non è presente, leggilo dalla 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 eliminare il vecchio documento. Aumenta gradualmente le letture parallele per assicurarti 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 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 il batch di utenti e utilizza le letture parallele per gli utenti nel corso della migrazione.
Tieni presente che non puoi eseguire facilmente il rollback a meno che non esegui scritture doppie sia delle entità vecchie che di quelle nuove 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 potrebbe essere conservato oltre la durata del progetto.
- Come best practice per la conformità dei dati, ti consigliamo di non memorizzare informazioni sensibili nei nomi dei documenti e 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 delle regole potrebbe evitare uno scenario in cui un utente malintenzionato scarichi ripetutamente l'intero database.
Scopri di più sull'utilizzo di Cloud Firestore Security Rules.