Utilizza le best practice qui elencate come riferimento rapido quando crei un'applicazione che utilizza Cloud Firestore.
Località del database
Quando crei l'istanza del database, seleziona la località del database più vicina agli utenti e alle risorse di computing. Gli hop di rete a lungo raggio sono più soggetti a errori e aumentano la latenza delle query.
Per massimizzare la disponibilità e la durabilità di l'applicazione, seleziona una località multi-regione e posiziona le risorse di computing critiche in almeno due regioni.
Seleziona una località regionale per ridurre i costi, la latenza di scrittura se la tua applicazione è sensibile alla latenza o per la co-locazione con altre risorse GCP.
ID dei documenti
- Evita gli ID documento
.e... - Evita di utilizzare le barre
/negli ID documento. Non utilizzare ID documento che aumentano in modo monotono, 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 una sequenza di escape aggiuntiva:
.punto[parentesi quadra aperta]parentesi quadra chiusa*asterisco`accento grave
Indici
Ridurre la latenza di scrittura
Il principale fattore che contribuisce alla latenza di scrittura è il fanout dell'indice. Le best practice per ridurre il fanout dell'indice sono:
Imposta le esenzioni degli indici a livello di raccolta. Un'impostazione predefinita semplice consiste nel disattivare l'indicizzazione discendente e degli array. La rimozione dei valori indicizzati non utilizzati 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 in blocco anziché lo scrittore batch atomico.
Esenzioni degli indici
Per la maggior parte delle app, puoi fare affidamento sull'indicizzazione automatica e sui link ai messaggi di errore per gestire gli indici. Tuttavia, potresti voler aggiungere esenzioni a campo singolo nei seguenti casi:
| Custodia | Descrizione |
|---|---|
| Campi stringa di grandi dimensioni | Se hai 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. |
| 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 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 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 le policy TTL (time-to-live), tieni presente che il campo TTL deve essere un timestamp. L'indicizzazione sui campi TTL è attivata per impostazione predefinita e può influire sulle prestazioni a frequenze di traffico più elevate. Come best practice, aggiungi esenzioni di indicizzazione automatica per i campi TTL. |
| Campi array o mappa di grandi dimensioni | I campi array o mappa di grandi dimensioni possono avvicinarsi al limite di 40.000 voci di indice per documento. Se non esegui query in base a un campo array o 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 saperne di più, consulta Aggiornamenti di 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 richiede il risultato di una ricerca di documenti e i risultati di una query prima di 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 avviare la query.
Non utilizzare offset. Utilizza invece i cursori. L'utilizzo di un offset evita solo di restituire i documenti ignorati all'applicazione, ma questi documenti vengono comunque recuperati internamente. I documenti ignorati influiscono sulla latenza della query e all'applicazione vengono addebitate le operazioni di lettura necessarie per recuperarli.
Ripetizioni delle transazioni
Gli Cloud Firestore SDK e le librerie client di Cloud Firestore riprovano automaticamente le transazioni non riuscite per gestire gli errori temporanei. Se la tua applicazione accede Cloud Firestore direttamente tramite le API REST o RPC anziché tramite un SDK, deve implementare i tentativi di ripetizione delle transazioni 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.
Progettare per la scalabilità
Le seguenti best practice descrivono come evitare situazioni che creano problemi di contesa.
Aggiornamenti di un singolo documento
Quando progetti l'app, considera la velocità con cui aggiorna i singoli documenti. Il modo migliore per caratterizzare il rendimento 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 contesa tra le richieste e il numero di indici interessati.
Un'operazione di scrittura di documenti aggiorna il documento e gli indici associati, e Cloud Firestore applica in modo sincrono l'operazione di scrittura a un quorum di repliche. A frequenze di scrittura sufficientemente elevate, il database inizierà a riscontrare contesa, latenza più elevata o altri errori.
Frequenze di lettura, scrittura ed eliminazione elevate in un intervallo di documenti ristretto
Evita frequenze di lettura o scrittura elevate per i documenti vicini in ordine lessicografico, altrimenti l'applicazione riscontrerà errori di contesa. Questo problema è noto come hotspotting e la tua applicazione può riscontrarlo se esegue una delle seguenti operazioni:
Crea nuovi documenti a una frequenza molto elevata e alloca i propri ID che aumentano in modo monotono.
Cloud Firestore alloca gli ID documento utilizzando un algoritmo di dispersione. Non dovresti riscontrare hotspotting nelle scritture se crei nuovi documenti utilizzando gli ID documento automatici.
Crea nuovi documenti a una frequenza elevata in una raccolta con pochi documenti.
Crea nuovi documenti con un campo che aumenta in modo monotono, ad esempio un timestamp, a una frequenza molto elevata.
Elimina documenti in una raccolta a una frequenza elevata.
Scrive nel database a una frequenza molto elevata senza aumentare gradualmente il traffico.
Evitare di saltare i dati eliminati
Evita le query che saltano i dati eliminati di recente. Una query potrebbe dover saltare un numero elevato di voci di indice se i risultati della query iniziali sono stati eliminati di recente.
Un esempio di carico di lavoro che potrebbe dover saltare molti dati eliminati è quello che tenta di trovare le voci di lavoro in coda più vecchie. La query potrebbe essere simile alla seguente:
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 in tutti i documenti eliminati di recente. Questo 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 precedente utilizza un campo che aumenta in modo monotono, che è un anti-pattern per frequenze di scrittura elevate.
Aumentare il traffico
Dovresti aumentare gradualmente il traffico verso le nuove raccolte o i documenti vicini in ordine lessicografico per dare a Cloud Firestore un 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 poi aumentare il traffico del 50% ogni 5 minuti. Puoi aumentare in modo simile il traffico di scrittura, ma tieni presente i Cloud Firestore limiti standard. Assicurati che le operazioni siano distribuite in modo relativamente uniforme nell'intervallo di chiavi. Questa è la cosiddetta regola "500/50/5".
Migrazione del traffico a una nuova raccolta
L'aumento graduale è particolarmente importante se esegui la migrazione del traffico dell'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, questo potrebbe causare un aumento improvviso del traffico verso i documenti vicini in ordine lessicografico 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 documento di molti documenti all'interno della stessa raccolta.
La strategia migliore 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 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 le letture parallele durante la migrazione del traffico a una nuova raccolta, leggi prima dalla vecchia raccolta. Se il documento non è presente, leggi dalla nuova raccolta. Una frequenza elevata di letture di documenti inesistenti può portare a hotspotting, quindi assicurati di aumentare gradualmente il carico sulla nuova raccolta. Una strategia migliore consiste nel 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 di scrivere in ID documento sequenziali per evitare gli hotspot. Al termine del job batch, puoi leggere solo dalla nuova raccolta.
Un perfezionamento di questa strategia consiste nel migrare piccoli batch di utenti alla volta. Aggiungi un campo al documento utente che tenga traccia dello stato di migrazione dell'utente. Seleziona un batch di utenti da migrare in base a un hash dell'ID utente. Utilizza un job batch per migrare i documenti per quel batch di utenti e utilizza le letture parallele per gli utenti a metà della migrazione.
Tieni presente che non puoi eseguire facilmente il rollback a meno che tu non esegua scritture doppie delle entità vecchie e nuove durante la fase di migrazione. In questo modo aumenteranno 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 archiviare informazioni sensibili nei nomi dei documenti e nei nomi dei campi dei documenti.
Impedire l'accesso non autorizzato
Impedisci operazioni non autorizzate sul database con Cloud Firestore Security Rules. Ad esempio, l'utilizzo delle regole potrebbe evitare uno scenario in cui un utente malintenzionato scarica ripetutamente l'intero database.
Scopri di più sull'utilizzo Cloud Firestore Security Rules.