Questa pagina descrive il concetto avanzato di sessioni in Spanner, tra cui best practice per le sessioni durante la creazione di una libreria client, utilizzando le API REST o RPC oppure le 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 è 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
Creare una sessione è costoso. Per evitare il costo delle prestazioni ogni volta viene eseguita un'operazione sul database, i client devono mantenere un pool di sessioni, ovvero di sessioni disponibili pronte all'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 le comunicazioni. Un canale gRPC è approssimativamente equivalente a una connessione TCP. Un canale gRPC può gestire fino a 100 richieste in parallelo. Ciò significa che un'applicazione dovrà avere un numero di canali gRPC pari al numero di richieste in parallelo che l'applicazione viene eseguito, 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 vengono descritte le best practice relative all'utilizzo del client Google librerie 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 sessioni e le transazioni simultanee eseguite dalla tua applicazione. Devi modificare il valore impostazioni predefinite del pool di sessioni solo se prevedi una singola istanza di applicazione per eseguire più transazioni simultanee rispetto a quelle che è in grado di 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 il singolo client. - Imposta
MaxSessions
sul numero massimo di transazioni simultanee che un che un singolo client possa eseguire. - Imposta
MinSessions=MaxSessions
se la contemporaneità prevista non cambia per tutta la durata 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 in contemporanea. Aumenta questo valore se noti una coda alta (latenza p95/p99), perché potrebbe indicare un valore di gRPC la congestione dei canali.
L'aumento del numero di sessioni attive utilizza risorse aggiuntive sul servizio di database Spanner e nella libreria client. L'aumento del di sessioni che vanno oltre l'effettiva necessità dell'applicazione potrebbe le prestazioni del tuo sistema.
Aumentare il pool di sessioni rispetto all'aumento del numero di client
La dimensione del pool di sessioni per un'applicazione determina il numero di sessioni transazioni che una singola istanza dell'applicazione può eseguire. Aumento della sessione dimensioni del pool oltre la contemporaneità massima che può essere eseguita da una singola istanza di applicazione è sconsigliato. Se l'applicazione riceve un picco 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 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.
Aumento delle dimensioni del pool di sessioni oltre il numero massimo di thread che una singola istanza di applicazione può gestire non è consigliabile. Invece, aumenta il numero di istanze dell'applicazione.
Gestisci la frazione delle 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 predefinita di sessioni di scrittura per C# è 0,2. Puoi modificare la frazione utilizzando il campo WriteSessionsFraction di SessionPoolOptions
.
Vai
Tutte le sessioni Go sono uguali. Non sono presenti sessioni di lettura o di sola lettura/scrittura.
Java
Tutte le sessioni Java sono uguali. Non sono presenti sessioni di lettura o di sola lettura/scrittura.
Node.js
Tutte le sessioni Node.js sono uguali. Non sono presenti sessioni di lettura o di sola 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 predefinita di sessioni di scrittura per Ruby è 0,3. Puoi modificare frazione utilizzando il client di inizializzazione.
Best practice per la creazione di una libreria client o l'utilizzo di REST/RPC
Di seguito vengono descritte le best practice per l'implementazione delle sessioni in un client libreria per Spanner o per l'utilizzo di sessioni con il comando REST o API 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 la dimensione limite inferiore al numero di transazioni simultanee previste e imposta il limite superiore associate a 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 avere non 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 può eliminare una sessione se quest'ultima è più di 28 giorni fa.
I tentativi di utilizzare una sessione eliminata restituiscono NOT_FOUND
. Se riscontri
creare e utilizzare una nuova sessione, aggiungere la nuova sessione al pool e
per rimuovere la sessione eliminata dal pool.
Mantenere attiva una sessione inattiva
Il servizio di database Spanner si riserva il diritto di eliminare un modello non utilizzato
durante la sessione. Se hai sicuramente bisogno di mantenere attiva una sessione di inattività, ad esempio,
previsto un aumento significativo a breve termine nell'uso del database, quindi puoi evitare
la sessione non 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 avviene ogni giorno dalle 9:00 alle 18:00, mantenere attive alcune sessioni inattive durante quel periodo, dato che è probabile richiesta 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 conservare un insieme di sessioni per evitare l'overhead della connessione.
Nascondi i dettagli della sessione all'utente della libreria client
Se stai creando una libreria client, non esporre le sessioni all'utente consumer della libreria client. Consentire al client di effettuare chiamate al database senza la complessità di creare e gestire le sessioni. Ad esempio, libreria client che nasconde i dettagli della sessione al consumer della libreria client, consulta la libreria client Spanner per Java.
Gestire gli errori relativi alle 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 inserimento potrebbe non riuscire con
ALREADY_EXISTS
anche se la riga non esisteva prima del
tentativo di scrittura. Questo può accadere se il server di backend ha eseguito il commit della mutazione, ma
non è stato in grado di comunicare l'esito positivo al cliente. In questo caso, la mutazione potrebbe essere riprovata, con conseguente errore ALREADY_EXISTS
.
Di seguito sono riportati alcuni modi per risolvere questo scenario quando implementi i tuoi libreria client o utilizza l'API REST:
- Struttura le scritture in modo che siano idempotenti.
- Utilizza operazioni di scrittura con protezione dalla riproduzione.
- Implementare un metodo che esegue "upert" logica: inserisci se è nuova o aggiorna se esiste.
- Gestisci l'errore per conto del cliente.
Mantieni connessioni stabili
Per ottenere le migliori prestazioni, la connessione che utilizzi per ospitare una sessione rimangono stabili. Quando la connessione che ospita una sessione cambia, Spanner potrebbe interrompere la transazione attiva sulla sessione e causare carico extra sul database mentre aggiorna i 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.
Monitora 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 fuga di sessione è un incidente in cui
vengono creati, ma non restituiti a un pool di sessioni per il riutilizzo).
ListSessions
ti consente di visualizzare i metadati relativi alle sessioni attive, ad esempio quando è stata creata una sessione e quando è stata utilizzata per l'ultima volta. Analisi di questi dati
ti indicheranno la direzione giusta durante la risoluzione dei problemi relativi alle sessioni. Se la maggior parte
sessioni attive non hanno un approximate_last_use_time
recente, questo potrebbe
indicano che le sessioni non vengono
riutilizzate correttamente dall'applicazione. Per ulteriori informazioni sul campo approximate_last_use_time
, consulta la guida di riferimento all'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 sessioni
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 sessioni sono spesso causate da transazioni problematiche eseguite per un periodo di tempo estremamente lungo non si sono impegnati.
Puoi configurare il pool di sessioni per risolvere automaticamente questi 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.
Il logging può anche aiutare a identificare queste transazioni problematiche. Se la registrazione è abilitata, 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 oppure potresti avere una perdita di sessioni. I log di avviso contengono tracce di transazioni che vengono 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.
Attiva la libreria client per risolvere automaticamente le transazioni inattive
Puoi consentire alla libreria client di inviare log di avviso e risolvere automaticamente le transazioni non attive 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 degli avvisi, 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 i log degli avvisi e rimuovere le transazioni inattive, 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 degli avvisi, 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 multiplex ti consentono di creare un numero illimitato di richieste simultanee contemporaneamente. Le sessioni multiplex hanno i seguenti vantaggi:
- Requisiti di risorse di backend ridotti. Ad esempio, evitano le attività di manutenzione della sessione associate alla gestione della proprietà della sessione e alla raccolta dei rifiuti.
- Sessione di lunga durata che non richiede richieste keep-alive in caso di inattività.
- Le librerie client tipiche possono utilizzare una sessione multiplex per ogni client. La di sessioni regolari in uso è inferiore per i client che usano multiplex per alcune operazioni rispetto ai client che utilizzano solo sessioni.
- Non è necessario avere affinità con un solo canale gRPC. I client possono inviare richieste su più canali per la stessa sessione multiplexata.
Le sessioni multiplex supportano quanto segue:
- 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
Utilizza le metriche OpenTelemetry per vedere come viene suddiviso il traffico tra il pool di sessioni esistente e la sessione multiplexata. OpenTelemetry ha
un filtro per le metriche, is_multiplexed
, che mostra le sessioni multiplex se impostato su
true
.
Le sessioni multiplex sono attivate per impostazione predefinita per l'adattatore JDBC e PG. Per Java e Go librerie client, è disabilitata per impostazione predefinita. Puoi utilizzare Libreria client Java o libreria client Go per attivare sessioni multiplex. Per attivare una sessione multiplexata utilizzando Java o Go, consulta Attivare le sessioni multiplexate.
Attiva sessioni multiplex
Per attivare le sessioni multiplexate utilizzando il client Java o Go, imposta
GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS
su true
.
export GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS=TRUE
Visualizzare il traffico per le sessioni standard e multiplex
Opentelemetry ha il filtro is_multiplexed
per mostrare il traffico per
sessioni multiplex. Imposti questo filtro su true to view multiplexed sessions
and
false per visualizzare le sessioni regolari.
- Configurare Opentelemetry per Spanner utilizzando le procedure in Spanner Opentelemetry Prima di iniziare .
Vai a Esplora metriche.
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 sessioni regolari. b.is_multiplexed = true
per visualizzare le sessioni multiplex.Nell'immagine seguente viene mostrata l'opzione Filtro con sessioni multiplex selezionato.
Per saperne di più sull'uso di OpenTelemetry con Spanner, vedi Sfruttare OpenTelemetry per democratizzare Spanner Observability e Esaminare la latenza in un componente Spanner con OpenTelemetry.