Questa pagina descrive il concetto avanzato di 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 vengono eseguite più transazioni, la sessione viene chiamata sessione multiplexata.
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 delle prestazioni ogni volta che viene eseguita un'operazione di database, i client devono mantenere un pool di sessioni, ovvero un pool di sessioni disponibili pronte all'uso. Il pool deve archiviare 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 Spanner, ad esempio la libreria client Go o la libreria client Java.
Le sessioni sono pensate per durare a lungo, quindi dopo che una sessione viene 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 equivale approssimativamente a una connessione TCP. Un canale gRPC può gestire fino a 100 richieste simultanee. Ciò significa che un'applicazione avrà bisogno di almeno un numero di canali gRPC pari al numero di richieste simultanee che l'applicazione eseguirà, diviso per 100.
Il client Spanner crea un pool di canali gRPC quando lo crei.
Best practice per l'utilizzo delle librerie client Google
Di seguito sono descritte le best practice per l'utilizzo delle librerie client 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. Entrambi i valori predefiniti sono adeguati 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 dall'applicazione è uguale al numero di transazioni simultanee eseguite dall'applicazione. Devi modificare le impostazioni del pool di sessioni predefinito solo se prevedi che una singola istanza dell'applicazione esegua più transazioni simultanee di quelle che il pool di sessioni predefinito può gestire.
Per le applicazioni ad alta 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 il ciclo di vita dell'applicazione. Ciò impedisce lo scale up o lo scale down del pool di sessioni. Anche lo scale up o lo scale down 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 osservi una latenza di coda elevata (latenza p95/p99), perché potrebbe essere un'indicazione di congestione del canale gRPC.
L'aumento del numero di sessioni attive utilizza risorse aggiuntive nel 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 anziché il numero di client
Le dimensioni del pool di sessioni per un'applicazione determinano il numero di transazioni simultanee che una singola istanza dell'applicazione può eseguire. Non è consigliabile aumentare le dimensioni del pool di sessioni oltre la concorrenza massima che una singola istanza dell'applicazione può gestire. Se l'applicazione riceve un burst di richieste che supera il 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 utilizzato dalla libreria client è uguale al numero massimo di query simultanee eseguite dall'applicazione. Questi thread si aggiungono a quelli che l'applicazione utilizza 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. Aumenta invece 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 richiedono
spanner.databases.beginOrRollbackReadWriteTransaction
. Se l'utente ha il ruolo IAM
spanner.databaseReader
, la chiamata non va a buon fine
e Spanner restituisce questo 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 presenti sessioni di sola lettura o lettura/scrittura.
C#
La frazione predefinita di sessioni di scrittura per C# è 0,2. Puoi modificare la
frazione utilizzando il campo WriteSessionsFraction di
SessionPoolOptions
.
Vai
Tutte le sessioni di Go sono uguali. Non sono previste sessioni di sola lettura o lettura/scrittura.
Java
Tutte le sessioni Java sono uguali. Non sono presenti sessioni di sola lettura o lettura/scrittura.
Node.js
Tutte le sessioni di Node.js sono uguali. Non sono presenti sessioni di sola lettura o lettura/scrittura.
PHP
Tutte le sessioni PHP sono uguali. Non sono presenti 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 predefinita di sessioni di scrittura 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 stai sviluppando una libreria client o se stai utilizzando API REST/RPC. Se utilizzi una delle librerie client di Google per Spanner, consulta Best practice per l'utilizzo delle librerie client di Google.
Creare e dimensionare il 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 nel servizio di database Spanner, pertanto la mancata pulizia delle sessioni inutilizzate può peggiorare le prestazioni. Per gli utenti che lavorano con l'API RPC, consigliamo di non superare le 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 ha più di 28 giorni.
I tentativi di utilizzo di una sessione eliminata generano NOT_FOUND
. Se si verifica
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 inutilizzata. Se devi assolutamente mantenere attiva una sessione inattiva, ad esempio se è previsto un aumento significativo dell'utilizzo del database nel breve termine, puoi impedire l'interruzione della sessione. Esegui un'operazione economica, ad esempio
l'esecuzione della query SQL SELECT 1
, per mantenere attiva la sessione. Se hai una sessione inattiva che non è necessaria per l'utilizzo a breve termine, lascia che Spanner la elimini e poi creane una nuova la volta successiva che ne avrai bisogno.
Uno scenario per mantenere attive le sessioni è gestire la normale domanda di picco sul database. Se l'utilizzo intenso del database si verifica ogni giorno dalle 9:00 alle 18:00, devi mantenere attive alcune sessioni inattive durante questo periodo, poiché è probabile che siano 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 è se hai un'applicazione che utilizza Spanner, ma deve evitare l'overhead di connessione quando lo fa. Puoi mantenere attivo un insieme di sessioni per evitare l'overhead di connessione.
Nascondere i dettagli della sessione all'utente della libreria client
Se stai creando una libreria client, non esporre le sessioni al consumer della libreria client. Offri al client la possibilità di effettuare chiamate al database senza la complessità di creare e gestire le sessioni. Per un esempio di libreria client che nasconde i dettagli della sessione al consumer della libreria client, consulta la libreria client Spanner per Java.
Gestisci gli errori per le transazioni di scrittura non idempotenti
Le transazioni di scrittura senza protezione dal replay potrebbero applicare mutazioni più di una volta.
Se una mutazione non è idempotente, una mutazione applicata più di una volta potrebbe
causare un errore. Ad esempio, un inserimento potrebbe non riuscire con
ALREADY_EXISTS
anche se la riga non esisteva prima del
tentativo di scrittura. Ciò può verificarsi se il server di backend ha eseguito la mutazione, ma non è stato in grado di comunicare l'esito positivo al client. In questo caso, il tentativo di mutazione
potrebbe essere ripetuto, causando l'errore ALREADY_EXISTS
.
Ecco alcuni modi possibili per affrontare 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 dalla riproduzione.
- Implementa un metodo che esegue la logica "upsert": inserisci se nuovo o aggiorna se esiste.
- Gestisci l'errore per conto del client.
Mantenere connessioni stabili
Per ottenere prestazioni ottimali, la connessione che utilizzi 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 piccolo carico aggiuntivo sul database durante l'aggiornamento dei metadati della sessione. È normale che alcune connessioni cambino sporadicamente, ma devi evitare situazioni che comportino la modifica di 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 tuo 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 restituite a un pool di sessioni per
il riutilizzo.)
ListSessions
ti consente di visualizzare i metadati relativi alle tue sessioni attive, inclusi la data di creazione e l'ultimo utilizzo. L'analisi di questi dati ti
indicherà la direzione giusta per la risoluzione dei problemi relativi alle sessioni. Se la maggior parte delle sessioni attive
non ha un approximate_last_use_time
recente, ciò potrebbe indicare
che le sessioni non vengono riutilizzate correttamente dalla tua applicazione. Per ulteriori informazioni sul campo approximate_last_use_time
, consulta il riferimento
all'API RPC.
Per saperne di più sull'utilizzo di ListSessions
, consulta il riferimento API REST, il riferimento API RPC o il riferimento allo strumento a riga di comando gcloud.
Pulizia automatica delle perdite di sessione
Quando utilizzi tutte le sessioni nel pool di sessioni, ogni nuova transazione attende che una sessione venga restituita al pool. Quando le sessioni vengono create ma non vengono restituite al pool di sessioni per essere riutilizzate, si parla di perdita di sessione. Quando si verifica una 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 non confermate.
Puoi configurare il pool di sessioni in modo da risolvere automaticamente queste transazioni inattive. Quando abiliti la libreria client per risolvere automaticamente la transizione inattiva, identifica le transazioni problematiche che potrebbero causare una perdita di sessione, le rimuove dal pool di sessioni e le sostituisce con una nuova sessione.
La registrazione può anche aiutare a identificare queste transazioni problematiche. Se il logging è abilitato, i log di avviso vengono condivisi per impostazione predefinita quando è in uso più del 95% del pool di sessioni. Se l'utilizzo delle sessioni è superiore al 95%, devi aumentare il numero massimo di sessioni consentite nel pool di sessioni o potresti avere una perdita di sessioni. I log di avviso contengono stack trace delle transazioni che vengono eseguite più a lungo del previsto e possono aiutare 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.
Consentire alla libreria client di risolvere automaticamente le transazioni inattive
Puoi abilitare la libreria client per inviare log di avviso e risolvere automaticamente le transazioni inattive oppure abilitarla solo per ricevere log di avviso.
Java
Per ricevere i 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 consentono di creare un numero elevato di richieste simultanee in una singola sessione. Una sessione multiplex è un identificatore che utilizzi in più canali gRPC. Non introduce colli di bottiglia aggiuntivi. Le sessioni multiplexate presentano 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 garbage collection.
- Sessione di lunga durata che non richiede richieste keep-alive quando è inattiva.
Le sessioni multiplex sono supportate in:
- Le librerie client Java e Go.
Strumenti dell'ecosistema Spanner che dipendono dalle librerie client Java e Go, come PGAdapter, JDBC, Hibernate, driver database/sql e GORM.
Strumenti dell'ecosistema Spanner che dipendono dalle librerie client Java e Go, come PGAdapter, JDBC, Hibernate, driver di database o SQL e GORM. Puoi utilizzare le metriche OpenTelemetry per vedere come viene suddiviso il traffico tra il pool di sessioni esistente e la sessione multiplexata. OpenTelemetry ha un filtro delle metriche,
is_multiplexed
, che mostra le sessioni multiplexate quando è impostato sutrue
.
Le sessioni multiplexate sono supportate per tutti i tipi di transazioni.
Le librerie client ruotano le sessioni multiplexate ogni 7 giorni per evitare l'invio di transazioni su sessioni obsolete.
Le sessioni multiplex sono disattivate per impostazione predefinita. Devi utilizzare le variabili di ambiente per abilitare le sessioni multiplex prima di poterle utilizzare nelle tue applicazioni client. Per abilitare le sessioni multiplex utilizzando Java o Go, consulta Abilitare le sessioni multiplex.
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 query o istruzione DML non è riuscita, ci sono un paio di
scenari da considerare con le sessioni multiplexate. Le sessioni multiplex richiedono
che tu includa un token pre-commit generato dal server in ogni richiesta di commit. Per le
transazioni che contengono query o DML, deve esistere almeno una query o una transazione DML precedente
riuscita affinché il server invii un token valido alla
libreria client. Se non sono state eseguite query o transazioni DML
riusciti, la libreria client aggiunge implicitamente SELECT 1
prima di un commit.
Per una transazione di lettura o scrittura su 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 sessioni multiplexate
Per utilizzare le sessioni multiplex nelle applicazioni client, devi prima impostare una variabile di ambiente per abilitarle.
Per attivare le sessioni multiplex, imposta la variabile di ambiente
GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS
su TRUE
. Questo
flag attiva anche il supporto delle sessioni multiplexate per le transazioni ReadOnly
.
export GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS=TRUE
Per abilitare il supporto delle operazioni partizionate per le sessioni multiplexate, imposta la variabile di ambiente GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_PARTITIONED_OPS
su TRUE
.
export GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_PARTITIONED_OPS=TRUE
Per abilitare il supporto delle transazioni di lettura/scrittura per le sessioni multiplexate, 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 sessioni regolari e multiplex
Opentelemetry ha il 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 regolari.
- 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 multiplexate selezionate.
Per ulteriori informazioni sull'utilizzo di OpenTelemetry con Spanner, consulta Utilizzare OpenTelemetry per democratizzare l'osservabilità di Spanner e Esaminare la latenza in un componente Spanner con OpenTelemetry.