Leggi questo documento per prendere decisioni informate sulla progettazione dell'architettura delle tue applicazioni per garantire prestazioni e affidabilità elevate. Questo documento include argomenti avanzati relativi a Cloud Firestore. Se hai appena iniziato a utilizzare Cloud Firestore, consulta la guida rapida.
Cloud Firestore è un database flessibile e scalabile per lo sviluppo di dispositivi mobili, web e server di Firebase e Google Cloud. Iniziare a utilizzare Cloud Firestore e scrivere applicazioni complete e potenti è molto semplice.
Per assicurarti che le tue applicazioni continuino a funzionare correttamente man mano che le dimensioni del database e il traffico aumentano, è utile comprendere i meccanismi di lettura e scrittura nel backend di Cloud Firestore. Devi anche comprendere l'interazione delle letture e delle scritture con il livello di archiviazione e i vincoli sottostanti che potrebbero influire sulle prestazioni.
Consulta le sezioni seguenti per le best practice prima di progettare l'architettura della tua applicazione.
Comprendere i componenti di alto livello
Il seguente diagramma mostra i componenti di alto livello coinvolti in una richiesta API Cloud Firestore.

SDK e librerie client Cloud Firestore
Cloud Firestore supporta SDK e librerie client per diverse piattaforme. Sebbene un'app possa effettuare chiamate HTTP e RPC dirette all'API Cloud Firestore, le librerie client forniscono un livello di astrazione per semplificare l'utilizzo dell'API e implementare le best practice. Possono anche fornire funzionalità aggiuntive come l'accesso offline, le cache e così via.
Google Front End (GFE)
Si tratta di un servizio di infrastruttura comune a tutti i servizi Google Cloud. Il GFE accetta le richieste in entrata e le inoltra al servizio Google pertinente (il servizio Cloud Firestore in questo contesto). Inoltre, fornisce altre funzionalità importanti, tra cui la protezione dagli attacchi Denial of Service.
Servizio Cloud Firestore
Il servizio Cloud Firestore esegue controlli sulla richiesta API, tra cui autenticazione, autorizzazione, controlli delle quote e regole di sicurezza, oltre a gestire le transazioni. Questo servizio Cloud Firestore include un client di archiviazione che interagisce con il livello di archiviazione per le letture e le scritture dei dati.
Livello di archiviazione Cloud Firestore
Il livello di archiviazione di Cloud Firestore è responsabile dell'archiviazione dei dati e dei metadati, nonché delle funzionalità del database associate fornite da Cloud Firestore. Le sezioni seguenti descrivono come sono organizzati i dati nel livello di archiviazione Cloud Firestore e come viene scalato il sistema. Scoprire come sono organizzati i dati può aiutarti a progettare un modello di dati scalabile e a comprendere meglio le best practice di Cloud Firestore.
Intervalli e suddivisioni delle chiavi
Cloud Firestore è un database NoSQL orientato ai documenti. I dati vengono archiviati in documenti, organizzati in gerarchie di raccolte. La gerarchia delle raccolte e l'ID documento vengono tradotti in una singola chiave per ogni documento. I documenti vengono archiviati logicamente e ordinati lessicograficamente in base a questa singola chiave. Utilizziamo il termine intervallo di chiavi per fare riferimento a un intervallo di chiavi lessicograficamente contiguo.
Un tipico database Cloud Firestore è troppo grande per essere contenuto in una singola macchina fisica. Esistono anche scenari in cui il workload sui dati è troppo pesante per essere gestito da una singola macchina. Per gestire workload di grandi dimensioni, Cloud Firestore suddivide i dati in parti separate che possono essere archiviate e gestite da più macchine o server di archiviazione. Queste partizioni vengono create nelle tabelle del database in blocchi di intervalli di chiavi chiamati suddivisioni.
Replica sincrona
È importante notare che il database viene sempre replicato automaticamente e in modo sincrono. Le suddivisioni dei dati hanno repliche in zone diverse per mantenerle disponibili anche quando una zona diventa inaccessibile. La replica coerente nelle diverse copie della suddivisione è gestita dall'algoritmo Paxos per il consenso. Una replica di ogni suddivisione viene scelta per agire come leader Paxos, responsabile della gestione delle scritture in quella suddivisione. La replica sincrona ti consente di leggere sempre l'ultima versione dei dati da Cloud Firestore.
Il risultato complessivo è un sistema scalabile e ad alta affidabilità che offre basse latenze sia per le letture che per le scritture, indipendentemente dai workload pesanti e su larga scala.
Layout dei dati
Cloud Firestore è un database di documenti senza schema. Tuttavia, internamente i dati vengono disposti principalmente in due tabelle di tipo database relazionale nel livello di archiviazione, come segue:
- Tabella Documents: i documenti vengono archiviati in questa tabella.
- Tabella Indexes: in questa tabella sono memorizzate le voci dell'indice che consentono di ottenere risultati in modo efficiente e ordinati per valore dell'indice.
Il seguente diagramma mostra l'aspetto delle tabelle di un database Cloud Firestore con le suddivisioni. Le suddivisioni vengono replicate in tre zone diverse e a ogni suddivisione viene assegnato un leader Paxos.

Regione singola e multiregione a confronto
Quando crei un database, devi selezionare una regione o una multi-regione.
Una singola località regionale è una posizione geografica specifica, ad esempio us-west1. Le suddivisioni dei dati di un database Cloud Firestore hanno repliche in zone diverse all'interno della regione selezionata, come spiegato in precedenza.
Una località multiregionale è costituita da un insieme definito di regioni in cui sono archiviate le repliche del database. In un deployment multiregionale di Cloud Firestore, due delle regioni hanno repliche complete di tutti i dati nel database. Una terza regione ha una replica di controllo che non gestisce un set completo di dati, ma partecipa alla replica. Replicando i dati tra più regioni, questi sono disponibili per la scrittura e la lettura anche in caso di perdita di un'intera regione.
Per saperne di più sulle località di una regione, consulta Località Cloud Firestore.

Comprendi il ciclo di vita di una scrittura in Cloud Firestore
Un client Cloud Firestore può scrivere dati creando, aggiornando o eliminando un singolo documento. Una scrittura in un singolo documento richiede l'aggiornamento atomico sia del documento sia delle voci di indice associate nel livello di archiviazione. Cloud Firestore supporta anche operazioni atomiche costituite da più letture e/o scritture in uno o più documenti.
Per tutti i tipi di scrittura, Cloud Firestore fornisce le proprietà ACID (atomicità, coerenza, isolamento e durabilità) dei database relazionali. Cloud Firestore fornisce anche la serializzabilità, il che significa che tutte le transazioni vengono visualizzate come se fossero eseguite in un ordine seriale.
Passaggi di alto livello in una transazione di scrittura
Quando il client Cloud Firestore esegue una scrittura o un commit di una transazione, utilizzando uno dei metodi menzionati in precedenza, internamente viene eseguita come una transazione di lettura/scrittura del database nel livello di archiviazione. La transazione consente a Cloud Firestore di fornire le proprietà ACID menzionate in precedenza.
Come primo passaggio di una transazione, Cloud Firestore legge il documento esistente e determina le mutazioni da apportare ai dati nella tabella Documents.
Ciò include anche l'esecuzione degli aggiornamenti necessari alla tabella Indexes come segue:
- I campi che vengono aggiunti ai documenti devono avere inserimenti corrispondenti nella tabella Indexes.
- I campi che vengono rimossi dai documenti devono essere eliminati anche dalla tabella Indexes.
- I campi che vengono modificati nei documenti richiedono sia eliminazioni (per i valori precedenti) sia inserimenti (per i nuovi valori) nella tabella Indexes.
Per calcolare le mutazioni menzionate in precedenza, Cloud Firestore legge la configurazione di indicizzazione per il database. La configurazione di indicizzazione memorizza le informazioni sugli indici di un database. Cloud Firestore utilizza due tipi di indici: a campo singolo e composto. Per una comprensione dettagliata degli indici creati in Cloud Firestore, consulta Tipi di indici in Cloud Firestore.
Una volta calcolate le mutazioni, Cloud Firestore le raccoglie all'interno di una transazione e poi ne esegue il commit.
Comprendi una transazione di scrittura nel livello di archiviazione
Come spiegato in precedenza, una scrittura in Cloud Firestore comporta una transazione di lettura/scrittura nel livello di archiviazione. A seconda del layout dei dati, una scrittura potrebbe comportare una o più suddivisioni, come mostrato nel layout dei dati.
Nel diagramma seguente, il database Cloud Firestore ha otto suddivisioni (contrassegnate da 1 a 8) ospitate su tre diversi server di archiviazione in una singola zona e ogni suddivisione è replicata in 3(o più) zone diverse. Ogni divisione ha un leader Paxos, che potrebbe trovarsi in una zona diversa per divisioni diverse.
Suddivisione del database Cloud Firestore">
Considera un database Cloud Firestore con la raccolta Restaurants come segue:

Il client Cloud Firestore richiede la seguente modifica a un documento nella raccolta Restaurant aggiornando il valore del campo priceCategory.

I seguenti passaggi di alto livello descrivono cosa succede durante la scrittura:
- Crea una transazione di lettura/scrittura.
- Leggi il documento
restaurant1nella raccoltaRestaurantsdalla tabella Documenti dal livello di archiviazione. - Leggi gli indici del documento dalla tabella Indexes.
- Calcola le mutazioni da apportare ai dati. In questo caso, sono presenti cinque mutazioni:
- M1: aggiorna la riga per
restaurant1nella tabella Documents in modo da riflettere la modifica del valore del campopriceCategory. - M2 e M3: elimina le righe per il valore precedente di
priceCategorynella tabella Indexes per gli indici decrescenti e crescenti. - M4 e M5: inserisci le righe per il nuovo valore di
priceCategorynella tabella Indexes per gli indici decrescenti e crescenti.
- M1: aggiorna la riga per
- Esegui il commit di queste mutazioni.
Il client di archiviazione nel servizio Cloud Firestore cerca le suddivisioni che possiedono le chiavi delle righe da modificare. Prendiamo in considerazione un caso in cui la suddivisione 3 gestisce M1 e la suddivisione 6 gestisce M2-M5. Esiste una transazione distribuita che coinvolge tutte queste suddivisioni come partecipanti. Le suddivisioni dei partecipanti possono includere anche qualsiasi altra suddivisione da cui i dati sono stati letti in precedenza nell'ambito della transazione di lettura/scrittura.
I seguenti passaggi descrivono cosa succede durante il commit:
- Il client di archiviazione esegue un commit. Il commit contiene le mutazioni M1-M5.
- Le suddivisioni 3 e 6 sono i partecipanti a questa transazione. Uno dei partecipanti viene scelto come coordinatore, ad esempio Split 3. Il compito del coordinatore è assicurarsi che il commit o l'interruzione della transazione avvenga in modo atomico in tutti i partecipanti.
- Le repliche leader di queste suddivisioni sono responsabili del lavoro svolto dai partecipanti e dai coordinatori.
- Ogni partecipante e coordinatore esegue un algoritmo Paxos con le rispettive repliche.
- Il leader esegue un algoritmo Paxos con le repliche. Il quorum viene raggiunto se la maggior parte delle repliche risponde al leader con una risposta
ok to commit. - Ogni partecipante comunica quindi al coordinatore quando è pronto (prima fase del commit in due fasi). Se un partecipante non può eseguire il commit della transazione, l'intera transazione
aborts.
- Il leader esegue un algoritmo Paxos con le repliche. Il quorum viene raggiunto se la maggior parte delle repliche risponde al leader con una risposta
- Una volta che il coordinatore sa che tutti i partecipanti, incluso se stesso, sono pronti, comunica il risultato della transazione
accepta tutti i partecipanti (seconda fase del commit in due fasi). In questa fase, ogni partecipante registra la decisione di commit nello spazio di archiviazione stabile e viene eseguito il commit della transazione. - Il coordinatore risponde al client di archiviazione in Cloud Firestore che è stato eseguito il commit della transazione. In parallelo, il coordinatore e tutti i partecipanti applicano le mutazioni ai dati.

Quando il database Cloud Firestore è piccolo, può accadere che una singola suddivisione possieda tutte le chiavi nelle mutazioni M1-M5. In questo caso, la transazione ha un solo partecipante e il commit in due fasi menzionato in precedenza non è necessario, il che velocizza le scritture.
Scritture multiregione
In un deployment multiregionale, la distribuzione delle repliche tra le regioni aumenta la disponibilità, ma comporta un costo in termini di prestazioni. La comunicazione tra repliche in regioni diverse richiede tempi di round trip più lunghi. Pertanto, la latenza di base per le operazioni Cloud Firestore è leggermente superiore rispetto ai deployment in una singola regione.
Configuriamo le repliche in modo che la leadership per le suddivisioni rimanga sempre nella regione principale. La regione principale è quella da cui proviene il traffico in entrata verso il server Cloud Firestore. Questa decisione di leadership riduce il ritardo di andata e ritorno nella comunicazione tra il client di archiviazione in Cloud Firestore e il leader della replica (o il coordinatore per le transazioni con più suddivisioni).
Ogni scrittura in Cloud Firestore comporta anche un'interazione con il motore in tempo reale in Cloud Firestore. Per saperne di più sulle query in tempo reale, consulta Informazioni sulle query in tempo reale su larga scala.
Comprendi il ciclo di vita di una lettura in Cloud Firestore
Questa sezione approfondisce le letture autonome non in tempo reale in Cloud Firestore. Internamente, il server Cloud Firestore gestisce la maggior parte di queste query in due fasi principali:
- Una singola scansione dell'intervallo nella tabella Indexes
- Ricerca di punti nella tabella Documents in base al risultato della scansione precedente
Le letture dei dati dal livello di archiviazione vengono eseguite internamente utilizzando una transazione di database per garantire letture coerenti. Tuttavia, a differenza delle transazioni utilizzate per le scritture, queste transazioni non acquisiscono blocchi. Invece, funzionano scegliendo un timestamp, quindi eseguendo tutte le letture in quel timestamp. Poiché non acquisiscono blocchi, non bloccano le transazioni di lettura/scrittura simultanee. Per eseguire questa transazione, il client di archiviazione in Cloud Firestore specifica un limite di timestamp, che indica al livello di archiviazione come scegliere un timestamp di lettura. Il tipo di timestamp scelto dal client di archiviazione in Cloud Firestore è determinato dalle opzioni di lettura per la richiesta di lettura.
Comprendi una transazione di lettura nel livello di archiviazione
Questa sezione descrive i tipi di letture e il modo in cui vengono elaborati nel livello di archiviazione in Cloud Firestore.
Letture forti
Per impostazione predefinita, le letture di Cloud Firestore hanno un'elevata coerenza. Questa elevata coerenza significa che una lettura di Cloud Firestore restituisce l'ultima versione dei dati che riflette tutte le scritture di cui è stato eseguito il commit fino all'inizio della lettura.
Lettura di una singola suddivisione
Il client di archiviazione in Cloud Firestore cerca le suddivisioni che possiedono le chiavi delle righe da leggere. Supponiamo che debba eseguire una lettura dalla suddivisione 3 della sezione precedente. Il client invia la richiesta di lettura alla replica più vicina per ridurre la latenza di round trip.
A questo punto, potrebbero verificarsi i seguenti casi a seconda della replica scelta:
- La richiesta di lettura viene inviata a una replica leader (zona A).
- Poiché il leader è sempre aggiornato, la lettura può procedere direttamente.
- La richiesta di lettura viene inviata a una replica non leader (ad esempio, la zona B)
- La divisione 3 potrebbe sapere, in base al suo stato interno, di avere informazioni sufficienti per gestire la lettura e lo fa.
- La suddivisione 3 non è sicura di aver visto i dati più recenti. Invia un messaggio al leader per richiedere il timestamp dell'ultima transazione che deve applicare per gestire la lettura. Una volta applicata la transazione, la lettura può procedere.
Cloud Firestore restituisce quindi la risposta al client.
Lettura con suddivisione multipla
Nel caso in cui le letture debbano essere eseguite da più suddivisioni, lo stesso meccanismo si verifica in tutte le suddivisioni. Una volta restituiti i dati da tutte le suddivisioni, il client di archiviazione in Cloud Firestore combina i risultati. Cloud Firestore risponde quindi al client con questi dati.
Letture di dati obsoleti
Le letture strong sono la modalità predefinita in Cloud Firestore. Tuttavia, ciò comporta un costo di latenza potenzialmente più elevato a causa della comunicazione che potrebbe essere richiesta con il leader. Spesso l'applicazione Cloud Firestore non ha bisogno di leggere l'ultima versione dei dati e la funzionalità funziona bene con dati che potrebbero essere obsoleti di qualche secondo.
In questo caso, il client può scegliere di ricevere letture di dati obsoleti utilizzando le opzioni di lettura read_time. In questo caso, le letture vengono eseguite come se i dati fossero al momento read_time ed è molto probabile che la replica più vicina abbia già verificato di avere dati al momento read_time specificato.
Per prestazioni notevolmente migliori, 15 secondi è un valore di inattività ragionevole. Anche per le letture di dati obsoleti, le righe restituite sono coerenti tra loro.
Evita gli hotspot
Le suddivisioni in Cloud Firestore vengono suddivise automaticamente in parti più piccole per distribuire il lavoro di gestione del traffico a più server di archiviazione quando necessario o quando lo spazio delle chiavi si espande. Le suddivisioni create per gestire il traffico in eccesso vengono conservate per circa 24 ore anche se il traffico scompare. Pertanto, se si verificano picchi di traffico ricorrenti, le suddivisioni vengono mantenute e ne vengono introdotte altre ogni volta che è necessario. Questi meccanismi aiutano i database Cloud Firestore a scalare automaticamente in base all'aumento del carico di traffico o delle dimensioni del database. Tuttavia, esistono alcune limitazioni di cui tenere conto, come spiegato di seguito.
La suddivisione dello spazio di archiviazione e del carico richiede tempo e un aumento troppo rapido del traffico potrebbe causare una latenza elevata o errori di superamento della scadenza, comunemente definiti hotspot, mentre il servizio si adatta. La best practice consiste nel distribuire le operazioni nell'intervallo di chiavi, aumentando al contempo il traffico su una raccolta in un database con 500 operazioni al secondo. Dopo questo aumento graduale, aumenta il traffico fino al 50% ogni cinque minuti. Questo processo è chiamato regola 500/50/5 e posiziona il database in modo che possa scalare in modo ottimale per soddisfare il tuo workload.
Sebbene le suddivisioni vengano create automaticamente con l'aumento del carico, Cloud Firestore può suddividere un intervallo di chiavi solo fino a quando non gestisce un singolo documento utilizzando un insieme dedicato di server di archiviazione replicati. Di conseguenza, volumi elevati e sostenuti di operazioni simultanee su un singolo documento possono causare un hotspot su quel documento. Se riscontri latenze elevate prolungate su un singolo documento, ti consigliamo di modificare il modello di dati per suddividere o replicare i dati in più documenti.
Gli errori di conflitto si verificano quando più operazioni tentano di leggere e/o scrivere lo stesso documento contemporaneamente.
Un altro caso speciale di hotspotting si verifica quando una chiave che aumenta/diminuisce in sequenza viene utilizzata come ID documento in Cloud Firestore e il numero di operazioni al secondo è notevolmente elevato. La creazione di più suddivisioni non è utile in questo caso, poiché l'ondata di traffico si sposta semplicemente sulla suddivisione appena creata. Poiché Cloud Firestore indicizza automaticamente tutti i campi del documento per impostazione predefinita, questi hotspot in movimento possono essere creati anche nello spazio dell'indice per un campo del documento che contiene un valore che aumenta/diminuisce in sequenza, ad esempio un timestamp.
Tieni presente che, seguendo le pratiche descritte sopra, Cloud Firestore può scalare per gestire workload di dimensioni arbitrarie senza che tu debba modificare alcuna configurazione.
Risoluzione dei problemi
Cloud Firestore fornisce Key Visualizer come strumento di diagnostica progettato per analizzare i pattern di utilizzo e risolvere i problemi di hotspotting.
Passaggi successivi
- Scopri altre best practice
- Scopri di più sulle query in tempo reale su larga scala