Questa pagina descrive il concetto avanzato delle sessioni in Spanner, incluse le best practice per le sessioni durante la creazione di una libreria client, l'utilizzo delle API REST o RPC o l'utilizzo delle librerie client di Google.
Panoramica delle sessioni
Una sessione rappresenta un canale di comunicazione con il servizio di database Spanner. Una sessione viene utilizzata per eseguire transazioni che leggono, scrivono o modificano i dati in un database Spanner. Ogni sessione si applica a un singolo database.
Le sessioni possono eseguire una o più transazioni alla volta. Quando si eseguono più transazioni, la sessione viene chiamata sessione multiplex.
Le letture, le scritture e le query autonome utilizzano internamente una transazione.
Vantaggi in termini di prestazioni di un pool di sessioni
La creazione di una sessione è costosa. Per evitare il costo in termini di prestazioni ogni volta che viene eseguita un'operazione sul database, i client devono mantenere un pool di sessioni, ovvero un pool di sessioni disponibili e pronte per l'uso. Il pool deve memorizzare le sessioni esistenti e restituire il tipo di sessione appropriato quando richiesto, nonché gestire la pulizia delle sessioni inutilizzate. Per un esempio di come implementare un pool di sessioni, consulta il codice sorgente di una delle librerie client di Spanner, ad esempio la libreria client Go o la libreria client Java.
Le sessioni sono progettate per durare a lungo, quindi dopo che una sessione è stata utilizzata per un'operazione di database, il client deve restituirla al pool per il riutilizzo.
Panoramica dei canali gRPC
I canali gRPC vengono utilizzati dal client Spanner per la comunicazione. Un canale gRPC è approssimativamente equivalente a una connessione TCP. Un canale gRPC può gestire fino a 100 richieste simultanee. Ciò significa che un'applicazione avrà bisogno di almeno autanti canali gRPC quanto il numero di richieste in parallelo che eseguirà, diviso per 100.
Il client Spanner crea un pool di canali gRPC quando lo crei.
Best practice per l'utilizzo delle librerie client di Google
Di seguito sono descritte le best practice per l'utilizzo delle librerie client di Google per Spanner.
Configura il numero di sessioni e canali gRPC nei pool
Le librerie client hanno un numero predefinito di sessioni nel pool di sessioni e un numero predefinito di canali gRPC nel pool di canali. Entrambe le impostazioni predefinite sono adeguate per la maggior parte dei casi. Di seguito sono riportate le sessioni minime e massime predefinite e il numero predefinito di canali gRPC per ogni linguaggio di programmazione.
C++
MinSessions: 100
MaxSessions: 400
NumChannels: 4
C#
MinSessions: 100
MaxSessions: 400
NumChannels: 4
Vai
MinSessions: 100
MaxSessions: 400
NumChannels: 4
Java
MinSessions: 100
MaxSessions: 400
NumChannels: 4
Node.js
Il client Node.js non supporta più canali gRPC. Pertanto, è consigliabile creare più client anziché aumentare le dimensioni del pool di sessioni oltre 100 sessioni per un singolo client.
MinSessions: 25
MaxSessions: 100
PHP
Il client PHP non supporta un numero configurabile di canali gRPC.
MinSessions: 1
MaxSessions: 500
Python
Python supporta quattro diversi tipi di pool di sessioni che puoi utilizzare per gestire le sessioni.
Ruby
Il client Ruby non supporta più canali gRPC. Pertanto, è consigliabile creare più client anziché aumentare le dimensioni del pool di sessioni oltre 100 sessioni per un singolo client.
MinSessions: 10
MaxSessions: 100
Il numero di sessioni utilizzate dalla tua applicazione è uguale al numero di transazioni contemporaneamente eseguite dalla tua applicazione. Devi modificare le impostazioni del pool di sessioni predefinite solo se prevedi che una singola istanza dell'applicazione esegua più transazioni simultanee di quante possa gestire il pool di sessioni predefinito.
Per le applicazioni con elevata concorrenza, si consiglia quanto segue:
- Imposta
MinSessions
sul numero previsto di transazioni simultanee che un singolo client eseguirà. - Imposta
MaxSessions
sul numero massimo di transazioni simultanee che un singolo client può eseguire. - Imposta
MinSessions=MaxSessions
se la concorrenza prevista non cambia molto durante la vita dell'applicazione. In questo modo, il pool di sessioni non può essere scalato verso l'alto o verso il basso. Anche l'aumento o la riduzione del pool di sessioni consuma alcune risorse. - Imposta
NumChannels
suMaxSessions / 100
. Un canale gRPC può gestire fino a 100 richieste contemporaneamente. Aumenta questo valore se noti una latenza in coda elevata (latenza p95/p99), in quanto potrebbe indicare una congestione del canale gRPC.
L'aumento del numero di sessioni attive utilizza risorse aggiuntive sul servizio di database Spanner e nella libreria client. L'aumento del numero di sessioni oltre le esigenze effettive dell'applicazione potrebbe ridurre le prestazioni del sistema.
Aumentare il pool di sessioni rispetto all'aumento del numero di client
Le dimensioni del pool di sessioni per un'applicazione determinano il numero di transazioni in parallelo che una singola istanza dell'applicazione può eseguire. Non è consigliabile aumentare la dimensione del pool di sessioni oltre la concorrenza massima che una singola istanza dell'applicazione può gestire. Se l'applicazione riceve un picco di richieste superiore al numero di sessioni nel pool, le richieste vengono messe in coda in attesa che una sessione diventi disponibile.
Le risorse utilizzate dalla libreria client sono le seguenti:
- Ogni canale gRPC utilizza una connessione TCP.
- Ogni chiamata gRPC richiede un thread. Il numero massimo di thread utilizzati dalla libreria client è uguale al numero massimo di query simultanee eseguite dall'applicazione. Questi thread vengono visualizzati sopra tutti i thread utilizzati dall'applicazione per la propria logica di business.
Non è consigliabile aumentare le dimensioni del pool di sessioni oltre il numero massimo di thread che una singola istanza dell'applicazione può gestire. Al contrario, aumenta il numero di istanze dell'applicazione.
Gestire la frazione di sessioni di scrittura
Per alcune librerie client, Spanner riserva una parte delle sessioni per le transazioni di lettura/scrittura, chiamata frazione di sessioni di scrittura. Se la tua app utilizza tutte le sessioni di lettura, Spanner utilizza le sessioni di lettura/scrittura anche per le transazioni di sola lettura. Le sessioni di lettura/scrittura richiedonospanner.databases.beginOrRollbackReadWriteTransaction
. Se l'utente appartiene al ruolo IAM spanner.databaseReader
, la chiamata non va a buon fine e Spanner restituisce il seguente messaggio di errore:
generic::permission_denied: Resource %resource% is missing IAM permission:
spanner.databases.beginOrRollbackReadWriteTransaction
Per le librerie client che mantengono una frazione di sessioni di scrittura, puoi impostare la frazione di sessioni di scrittura.
C++
Tutte le sessioni C++ sono uguali. Non sono disponibili sessioni di sola lettura o lettura/scrittura.
C#
La frazione di sessioni di scrittura predefinita per C# è 0,2. Puoi modificare la frazione utilizzando il campo WriteSessionsFraction di SessionPoolOptions
.
Vai
Tutte le sessioni Go sono uguali. Non sono disponibili sessioni di sola lettura o lettura/scrittura.
Java
Tutte le sessioni Java sono uguali. Non sono disponibili sessioni di sola lettura o lettura/scrittura.
Node.js
Tutte le sessioni Node.js sono uguali. Non sono disponibili sessioni di sola lettura o lettura/scrittura.
PHP
Tutte le sessioni PHP sono uguali. Non sono disponibili sessioni di sola lettura o lettura/scrittura.
Python
Python supporta quattro diversi tipi di pool di sessioni che puoi utilizzare per gestire le sessioni di lettura e lettura/scrittura.
Ruby
La frazione di sessioni di scrittura predefinita per Ruby è 0,3. Puoi modificare la frazione utilizzando il metodo di inizializzazione del client.
Best practice per la creazione di una libreria client o l'utilizzo di REST/RPC
Di seguito sono descritte le best practice per l'implementazione delle sessioni in una libreria client per Spanner o per l'utilizzo delle sessioni con le API REST o RPC.
Queste best practice si applicano solo se sviluppi una libreria client o se utilizzi API REST/RPC. Se utilizzi una delle librerie client di Google per Spanner, consulta le best practice per l'utilizzo delle librerie client di Google.
Crea e definisci le dimensioni del pool di sessioni
Per determinare una dimensione ottimale del pool di sessioni per un processo client, imposta il limite inferiore sul numero di transazioni simultanee previste e il limite superiore su un numero di test iniziale, ad esempio 100. Se il limite superiore non è adeguato, aumentalo. L'aumento del numero di sessioni attive utilizza risorse aggiuntive sul servizio di database Spanner, pertanto la mancata pulizia delle sessioni inutilizzate può peggiorare le prestazioni. Per gli utenti che utilizzano l'API RPC, consigliamo di non avere più di 100 sessioni per canale gRPC.
Gestire le sessioni eliminate
Esistono tre modi per eliminare una sessione:
- Un cliente può eliminare una sessione.
- Il servizio di database Spanner può eliminare una sessione quando è inattiva per più di un'ora.
- Il servizio di database Spanner potrebbe eliminare una sessione se è stata attivata più di 28 giorni fa.
I tentativi di utilizzare una sessione eliminata generano l'errore NOT_FOUND
. Se riscontri questo errore, crea e utilizza una nuova sessione, aggiungila al pool e rimuovi la sessione eliminata dal pool.
Mantenere attiva una sessione inattiva
Il servizio di database Spanner si riserva il diritto di eliminare una sessione non utilizzata. Se devi mantenere attiva una sessione inattiva, ad esempio se è previsto un aumento significativo dell'utilizzo del database a breve termine, puoi impedire che la sessione venga abbandonata. Esegui un'operazione economica, ad esempio
l'esecuzione della query SQL SELECT 1
, per mantenere attiva la sessione. Se hai una sessione inattiva non necessaria per l'utilizzo a breve termine, lascia che Spanner la elimini e poi crea una nuova sessione la volta successiva che ne hai bisogno.
Uno scenario per mantenere attive le sessioni è gestire la domanda di picco regolare sul database. Se l'utilizzo intensivo del database si verifica ogni giorno dalle 9:00 alle 18:00, dovresti mantenere attive alcune sessioni inattive durante questo periodo di tempo, poiché probabilmente sono necessarie per il picco di utilizzo. Dopo le 18:00, puoi consentire a Spanner di eliminare le sessioni inattive. Prima delle 9:00 di ogni giorno, crea alcune nuove sessioni in modo che siano pronte per la domanda prevista.
Un altro scenario è quello in cui hai un'applicazione che utilizza Spanner, ma deve evitare il sovraccarico della connessione. Puoi mantenere attivo un insieme di sessioni per evitare il sovraccarico della connessione.
Nascondere i dettagli della sessione all'utente della raccolta client
Se stai creando una libreria client, non esporre le sessioni all'utente consumer della libreria client. Offrire al client la possibilità di effettuare chiamate al database senza la complessità della creazione e della gestione delle sessioni. Per un esempio di libreria client che nasconde i dettagli della sessione all'utente che la utilizza, consulta la libreria client Spanner per Java.
Gestire gli errori per le transazioni di scrittura che non sono idempotenti
Le transazioni di scrittura senza protezione da replay potrebbero applicare le mutazioni più di una volta.
Se una mutazione non è idempotente, l'applicazione di più mutazioni potrebbe provocare un errore. Ad esempio, un'operazione di inserimento potrebbe non riuscire con
ALREADY_EXISTS
anche se la riga non esisteva prima del
tentativo di scrittura. Questo può verificarsi se il server di backend ha eseguito il commit della mutazione, ma non è stato in grado di comunicare il buon esito al client. In questo caso, la mutazione potrebbe essere riprovata, con conseguente errore ALREADY_EXISTS
.
Ecco alcuni modi possibili per gestire questo scenario quando implementi la tua libreria client o utilizzi l'API REST:
- Struttura le scritture in modo che siano idempotenti.
- Utilizza le scritture con protezione da replay.
- Implementa un metodo che esegue la logica "upsert": inserisci se nuovo o aggiorna se esiste.
- Gestisci l'errore per conto del cliente.
Mantieni connessioni stabili
Per ottenere le migliori prestazioni, la connessione utilizzata per ospitare una sessione deve rimanere stabile. Quando la connessione che ospita una sessione cambia, Spanner potrebbe interrompere la transazione attiva nella sessione e causare un lieve aumento del carico sul database durante l'aggiornamento dei metadati della sessione. È normale se alcune connessioni cambiano sporadicamente, ma devi evitare situazioni che potrebbero modificare un numero elevato di connessioni contemporaneamente. Se utilizzi un proxy tra il client e Spanner, devi mantenere la stabilità della connessione per ogni sessione.
Monitorare le sessioni attive
Puoi utilizzare il comando ListSessions
per monitorare le sessioni attive nel database dalla riga di comando, con l'API REST o con l'API RPC. ListSessions
mostra le sessioni attive per un determinato database. Questa opzione è utile se devi trovare la causa di una perdita di sessione. Una perdita di sessione è un
incidente in cui le sessioni vengono create, ma non vengono restituite a un pool di sessioni per
riprodurle.
ListSessions
ti consente di visualizzare i metadati relativi alle sessioni attive, ad esempio quando è stata creata una sessione e quando è stata utilizzata l'ultima volta. L'analisi di questi dati ti aiuterà a risolvere i problemi relativi alle sessioni. Se la maggior parte delle sessioni attive non ha un approximate_last_use_time
recente, potrebbe indicare che le sessioni non vengono riutilizzate correttamente dall'applicazione. Per ulteriori informazioni sul campo approximate_last_use_time
, consulta la documentazione di riferimento dell'API RPC.
Per ulteriori informazioni sull'utilizzo di ListSessions
, consulta la documentazione di riferimento dell'API REST, la documentazione di riferimento dell'API RPC o la documentazione di riferimento dello strumento a riga di comando gcloud.
Pulizia automatica delle perdite di sessione
Quando utilizzi tutte le sessioni nel pool di sessioni, ogni nuova transazione aspetta che una sessione venga restituita al pool. Quando le sessioni vengono create, ma non vengono restituite al pool di sessioni per il riutilizzo, si parla di perdita di sessioni. In caso di perdita di sessione, le transazioni in attesa di una sessione aperta rimangono bloccate indefinitamente e bloccano l'applicazione. Le perdite di sessione sono spesso causate da transazioni problematiche in esecuzione per un periodo di tempo estremamente lungo e che non vengono committate.
Puoi configurare il pool di sessioni in modo da risolvere automaticamente queste transazioni non attive. Quando attivi la libreria client per risolvere automaticamente la transizione non attiva, vengono identificate le transazioni problematiche che potrebbero causare una perdita di sessione, rimosse dal pool di sessioni e sostituite con una nuova sessione.
La registrazione può anche aiutarti a identificare queste transazioni problematiche. Se il logging è abilitato, i log di avviso vengono condivisi per impostazione predefinita quando più del 95% del pool di sessioni è in uso. Se l'utilizzo delle sessioni è superiore al 95%, devi aumentare il numero massimo di sessioni consentite nel pool di sessioni oppure potresti avere una perdita di sessioni. I log di avviso contengono tracce di transazioni eseguite per più tempo del previsto e possono contribuire a identificare la causa dell'utilizzo elevato del pool di sessioni. I log di avviso vengono inviati in base alla configurazione dell'esportatore di log.
Consenti alla libreria client di risolvere automaticamente le transazioni non attive
Puoi consentire alla libreria client di inviare log di avviso e risolvere automaticamente le transazioni inattive oppure di ricevere solo log di avviso.
Java
Per ricevere log di avviso e rimuovere le transazioni non attive, utilizza setWarnAndCloseIfInactiveTransactions
.
final SessionPoolOptions sessionPoolOptions = SessionPoolOptions.newBuilder().setWarnAndCloseIfInactiveTransactions().build()
final Spanner spanner =
SpannerOptions.newBuilder()
.setSessionPoolOption(sessionPoolOptions)
.build()
.getService();
final DatabaseClient client = spanner.getDatabaseClient(databaseId);
Per ricevere solo i log di avviso, utilizza
setWarnIfInactiveTransactions
.
final SessionPoolOptions sessionPoolOptions = SessionPoolOptions.newBuilder().setWarnIfInactiveTransactions().build()
final Spanner spanner =
SpannerOptions.newBuilder()
.setSessionPoolOption(sessionPoolOptions)
.build()
.getService();
final DatabaseClient client = spanner.getDatabaseClient(databaseId);
Vai
Per ricevere log di avviso e rimuovere le transazioni non attive, utilizza
SessionPoolConfig
con InactiveTransactionRemovalOptions
.
client, err := spanner.NewClientWithConfig(
ctx, database, spanner.ClientConfig{SessionPoolConfig: spanner.SessionPoolConfig{
InactiveTransactionRemovalOptions: spanner.InactiveTransactionRemovalOptions{
ActionOnInactiveTransaction: spanner.WarnAndClose,
}
}},
)
if err != nil {
return err
}
defer client.Close()
Per ricevere solo i log di avviso, utilizza customLogger
.
customLogger := log.New(os.Stdout, "spanner-client: ", log.Lshortfile)
// Create a logger instance using the golang log package
cfg := spanner.ClientConfig{
Logger: customLogger,
}
client, err := spanner.NewClientWithConfig(ctx, db, cfg)
Sessioni multiplex
Le sessioni multiplexate ti consentono di creare un numero elevato di richieste in parallelo in una singola sessione. Una sessione multiplexata è un identificatore che viene utilizzato su più canali gRPC. Non introduce ulteriori colli di bottiglia. Le sessioni multiplex hanno i seguenti vantaggi:
- Riduzione del consumo di risorse di backend grazie a un protocollo di gestione delle sessioni più semplice. Ad esempio, evitano le attività di manutenzione della sessione associate alla manutenzione della proprietà della sessione e alla raccolta dei rifiuti.
Sessione a lungo termine che non richiede richieste keep-alive in stato inattivo.
Le librerie client Java e Go".
Strumenti dell'ecosistema Spanner che dipendono dalle librerie client Java e Go, come PGAdapter, JDBC, Hibernate, database/sql driver e GORM.
API Spanner per le transazioni di sola lettura
Le librerie client Java e Go.
Strumenti dell'ecosistema Spanner che dipendono dalle librerie client Java e Go, come PGAdapter, JDBC, Hibernate, database o driver SQL e GORM. Puoi utilizzare le metriche OpenTelemetry per vedere in che modo il traffico viene suddiviso tra il pool di sessioni esistente e la sessione multiplexata. OpenTelemetry ha un filtro metrica,
is_multiplexed
, che mostra le sessioni multiplexate se impostato sutrue
.
Le sessioni multiplex sono supportate per tutti i tipi di transazioni.
Le librerie client ruotano le sessioni multiplexate ogni 7 giorni per evitare di inviare transazioni su sessioni non aggiornate.
Le sessioni multiplex sono disattivate per impostazione predefinita. Devi utilizzare le variabili di ambiente per attivare le sessioni multiplexate prima di poterle utilizzare nelle applicazioni client. Per attivare le sessioni multiplexate utilizzando Java o Go, consulta Attivare le sessioni multiplexate.
Considerazioni
Se stai tentando di eseguire il commit di un corpo di transazione di lettura o scrittura vuoto o di una transazione in cui ogni istruzione DML o query non è riuscita, ci sono un paio di scenari da considerare con le sessioni multiplex. Le sessioni multiplex richiedono
di includere un token pre-commit generato dal server in ogni richiesta di commit. Per le transazioni che contengono query o DML, deve essere stata eseguita almeno una query o transazione DML precedente affinché il server invii un token valido alla libreria client. Se non sono state eseguite query o transazioni DML con esito positivo, la libreria client aggiunge implicitamente SELECT 1
prima di un commit.
Per una transazione di lettura o scrittura in una sessione multiplexata che contiene solo mutazioni, se una delle mutazioni riguarda una tabella o una colonna che NON esiste nello schema, il client potrebbe restituire un errore INVALID_ARGUMENT
anziché un errore NOT_FOUND
.
Abilita le sessioni multiplex
Per utilizzare le sessioni multiplexate nelle applicazioni client, devi prima impostare una variabile di ambiente per attivarle.
Per attivare le sessioni multiplex, imposta la variabile di ambiente GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS
su TRUE
. Questo
flag abilita anche il supporto delle sessioni multiplex per le transazioni ReadOnly
.
export GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS=TRUE
Per abilitare il supporto delle operazioni partizionate per le sessioni multiplex, imposta la variabile di ambiente GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_PARTITIONED_OPS
su TRUE
.
export GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_PARTITIONED_OPS=TRUE
Per attivare il supporto delle transazioni di lettura/scrittura per le sessioni multiplex, imposta la variabile di ambiente GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_FOR_RW
su TRUE
.
export GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_FOR_RW=True
Devi impostare GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS
su TRUE
come
prerequisito per supportare una transazione in una sessione multiplexata.
Visualizzare il traffico per le sessioni standard e multiplex
OpenTelemetry dispone del filtro is_multiplexed
per mostrare il traffico per le sessioni multiplexate. Imposta questo filtro su true to view multiplexed sessions
and
false` per visualizzare le sessioni normali.
- Configura OpenTelemetry per Spanner utilizzando le procedure descritte nella sezione Prima di iniziare di OpenTelemetry per Spanner.
Vai a Metrics Explorer.
Nel menu a discesa Metrica, filtra in base a
generic
.Fai clic su Attività generica e vai a Spanner > Spanner/num_acquired_sessions.
Nel campo Filtro, seleziona una delle seguenti opzioni:
a.
is_multiplexed = false
per visualizzare le sessioni regolari. b.is_multiplexed = true
per visualizzare le sessioni multiplexate.L'immagine seguente mostra l'opzione Filtra con le sessioni multiplex selezionate.
Per ulteriori informazioni sull'utilizzo di OpenTelemetry con Spanner, consulta Sfruttare OpenTelemetry per democratizzare l'osservabilità di Spanner e Esaminare la latenza in un componente Spanner con OpenTelemetry.