Cette page décrit le concept avancé de "session" dans Spanner, et présente différentes bonnes pratiques liées à cette notion lors de la création d'une bibliothèque cliente, de l'utilisation des API REST ou RPC, ou de l'utilisation des bibliothèques clientes Google.
Présentation des sessions
Les sessions représentent un canal de communication avec le service de base de données Spanner. Elles servent à effectuer des transactions qui lisent, écrivent ou modifient des données dans une base de données Spanner. Chaque session s'applique à une base de données unique.
Les sessions peuvent exécuter une ou plusieurs transactions à la fois. Lorsque vous effectuez plusieurs transactions, la session est appelée session multiplexée.
Les lectures, écritures et requêtes autonomes utilisent une transaction en interne.
Avantages en termes de performances d'un pool de sessions
Créer une session coûte cher. Pour éviter les coûts de performance chaque fois qu'une opération de base de données est effectuée, les clients doivent conserver un pool de sessions, qui est un pool de sessions disponibles prêtes à l'emploi. Le pool doit stocker les sessions existantes et renvoyer le type de session approprié en cas de demande, puis effectuer un nettoyage visant à éliminer les sessions inutilisées. Pour obtenir un exemple de mise en œuvre d'un pool de sessions, consultez le code source de l'une des bibliothèques clientes Spanner, comme la bibliothèque cliente Go ou la bibliothèque cliente Java.
Les sessions sont destinées à durer longtemps. Ainsi, une fois qu'une session a été utilisée pour une opération de base de données, le client doit la renvoyer dans le pool pour qu'elle puisse être réutilisée.
Présentation des canaux gRPC
Le client Spanner utilise les canaux gRPC pour la communication. Un canal gRPC équivaut à peu près à une connexion TCP. Un canal gRPC peut gérer jusqu'à 100 requêtes simultanées. Cela signifie qu'une application aura besoin d'au moins autant de canaux gRPC que le nombre de requêtes simultanées qu'elle exécutera, divisé par 100.
Le client Spanner crée un pool de canaux gRPC lorsque vous le créez.
Bonnes pratiques concernant l'utilisation des bibliothèques clientes Google
Vous trouverez ci-dessous les bonnes pratiques concernant l'utilisation des bibliothèques clientes Google pour Spanner.
Configurer le nombre de sessions et de canaux gRPC dans les pools
Les bibliothèques clientes disposent d'un nombre par défaut de sessions dans le pool de sessions et d'un nombre par défaut de canaux gRPC dans le pool de canaux. Les deux valeurs par défaut sont adaptées dans la plupart des cas. Vous trouverez ci-dessous le nombre minimal et maximal de sessions et le nombre par défaut de canaux gRPC pour chaque langage de programmation.
C++
MinSessions: 100
MaxSessions: 400
NumChannels: 4
C#
MinSessions: 100
MaxSessions: 400
NumChannels: 4
Go
MinSessions: 100
MaxSessions: 400
NumChannels: 4
Java
MinSessions: 100
MaxSessions: 400
NumChannels: 4
Node.js
Le client Node.js n'est pas compatible avec plusieurs canaux gRPC. Il est donc recommandé de créer plusieurs clients au lieu d'augmenter la taille du pool de sessions au-delà de 100 sessions pour un seul client.
MinSessions: 25
MaxSessions: 100
PHP
Le client PHP n'est pas compatible avec un nombre configurable de canaux gRPC.
MinSessions: 1
MaxSessions: 500
Python
Python accepte quatre types de pools de sessions différents que vous pouvez utiliser pour gérer les sessions.
Ruby
Le client Ruby n'est pas compatible avec plusieurs canaux gRPC. Il est donc recommandé de créer plusieurs clients au lieu d'augmenter la taille du pool de sessions au-delà de 100 sessions pour un seul client.
MinSessions: 10
MaxSessions: 100
Le nombre de sessions utilisées par votre application est égal au nombre de transactions simultanées qu'elle exécute. Vous ne devez modifier les paramètres du pool de sessions par défaut que si vous prévoyez qu'une seule instance d'application exécutera plus de transactions simultanées que le pool de sessions par défaut ne peut gérer.
Pour les applications à forte concurrence, nous vous recommandons les éléments suivants:
- Définissez
MinSessions
sur le nombre attendu de transactions simultanées qu'un seul client exécutera. - Définissez
MaxSessions
sur le nombre maximal de transactions simultanées qu'un seul client peut exécuter. - Définissez
MinSessions=MaxSessions
si la concurrence attendue ne change pas beaucoup pendant la durée de vie de l'application. Cela empêche le pool de sessions de s'étendre ou de se réduire. L'ajustement à la hausse ou à la baisse du pool de sessions consomme également des ressources. - Définissez
NumChannels
surMaxSessions / 100
. Un canal gRPC peut gérer jusqu'à 100 requêtes simultanément. Augmentez cette valeur si vous observez une latence de queue élevée (latence p95/p99), car cela peut indiquer une congestion du canal gRPC.
L'augmentation du nombre de sessions actives utilise des ressources supplémentaires dans le service de base de données Spanner et dans la bibliothèque cliente. Augmenter le nombre de sessions au-delà des besoins réels de l'application peut dégrader les performances de votre système.
Augmenter le pool de sessions plutôt que le nombre de clients
La taille du pool de sessions d'une application détermine le nombre de transactions simultanées qu'une seule instance d'application peut exécuter. Il n'est pas recommandé d'augmenter la taille du pool de sessions au-delà de la simultanéité maximale qu'une seule instance d'application peut gérer. Si l'application reçoit une rafale de requêtes qui dépasse le nombre de sessions dans le pool, les requêtes sont mises en file d'attente en attendant qu'une session devienne disponible.
Les ressources consommées par la bibliothèque cliente sont les suivantes:
- Chaque canal gRPC utilise une connexion TCP.
- Chaque appel gRPC nécessite un thread. Le nombre maximal de threads utilisés par la bibliothèque cliente est égal au nombre maximal de requêtes simultanées exécutées par l'application. Ces threads se superposent à tous les threads que l'application utilise pour sa propre logique métier.
Il est déconseillé d'augmenter la taille du pool de sessions au-delà du nombre maximal de threads qu'une seule instance d'application peut gérer. Augmentez plutôt le nombre d'instances d'application.
Gérer la fraction des sessions d'écriture
Pour certaines bibliothèques clientes, Spanner réserve une partie des sessions pour les transactions en lecture-écriture, appelée fraction des sessions d'écriture. Si votre application consomme toutes les sessions de lecture, Spanner utilise les sessions de lecture-écriture, même pour les transactions en lecture seule. Les sessions en lecture/écriture nécessitent spanner.databases.beginOrRollbackReadWriteTransaction
. Si l'utilisateur possède un rôle IAM spanner.databaseReader
, l'appel échoue et Spanner renvoie le message d'erreur suivant:
generic::permission_denied: Resource %resource% is missing IAM permission:
spanner.databases.beginOrRollbackReadWriteTransaction
Vous pouvez définir la fraction de sessions d'écriture pour les bibliothèques clientes qui gèrent une fraction des sessions d'écriture.
C++
Les sessions C++ sont toutes similaires. Il n'existe pas de sessions en lecture seule ou en lecture-écriture.
C#
La fraction des sessions d'écriture par défaut pour C# est de 0,2. Vous pouvez modifier la fraction à l'aide du champ WriteSessionsFraction de SessionPoolOptions
.
Go
Les sessions Go sont toutes identiques. Il n'existe pas de sessions en lecture seule ou en lecture-écriture.
Java
Les sessions Java sont toutes similaires. Il n'existe pas de sessions en lecture seule ou en lecture-écriture.
Node.js
Toutes les sessions Node.js sont identiques. Il n'existe pas de sessions en lecture seule ou en lecture-écriture.
PHP
Les sessions PHP sont toutes similaires. Il n'existe pas de sessions en lecture seule ou en lecture-écriture.
Python
Python accepte quatre types de pools de sessions différents que vous pouvez utiliser pour gérer les sessions de lecture seule et de lecture-écriture.
Ruby
La fraction des sessions d'écriture par défaut pour Ruby est de 0,3. Vous pouvez la modifier à l'aide de la méthode d'initialisation du client.
Bonnes pratiques lors de la création d'une bibliothèque cliente ou de l'utilisation des API REST ou RPC
La section suivante décrit les bonnes pratiques relatives à la mise en œuvre de sessions dans une bibliothèque cliente pour Spanner, ou à l'utilisation de sessions avec les API REST ou RPC.
Ces bonnes pratiques ne s'appliquent que si vous développez une bibliothèque cliente ou si vous utilisez des API REST/RPC. Si vous utilisez l'une des bibliothèques clientes Google pour Spanner, reportez-vous à la page Bonnes pratiques concernant l'utilisation des bibliothèques clientes Google.
Créer et dimensionner le pool de sessions
Pour déterminer la taille optimale du pool de sessions pour un processus client, définissez la limite inférieure sur le nombre de transactions simultanées attendues, et la limite supérieure sur un numéro test initial, tel que 100. Si la limite supérieure n'est pas suffisante, augmentez-la. L'augmentation du nombre de sessions actives utilise des ressources supplémentaires dans le service de base de données Spanner. Ainsi, le fait de ne pas éliminer les sessions inutilisées peut dégrader les performances. Pour les utilisateurs qui se servent de l'API RPC, nous vous recommandons de ne pas avoir plus de 100 sessions par canal gRPC.
Gérer les sessions supprimées
Pour supprimer une session, trois méthodes s'offrent à vous :
- Un client peut supprimer une session.
- Le service de base de données Spanner peut supprimer une session lorsque celle-ci est inactive pendant plus d'une heure.
- Le service de base de données Spanner peut supprimer une session si celle-ci date de plus de 28 jours.
Les tentatives d'utilisation d'une session supprimée ont pour résultat NOT_FOUND
. Si vous rencontrez cette erreur, créez et utilisez une nouvelle session, ajoutez-la au pool et éliminez la session supprimée du pool.
Gérer l'activation d'une session inactive
Le service de base de données Spanner se réserve le droit de supprimer une session inutilisée. Si vous souhaitez absolument avoir la possibilité de réactiver une session inactive, par exemple, si vous prévoyez une augmentation importante de l'utilisation de la base de données à court terme, vous pouvez empêcher la suppression de la session. Effectuez une opération peu coûteuse telle que l'exécution de la requête SQL SELECT 1
pour maintenir la session active. Si vous disposez d'une session inactive qui n'est pas utile dans le court terme, autorisez sa suppression dans Spanner, puis créez une nouvelle session en fonction de vos nouveaux besoins.
Un scénario efficace pour garder les sessions actives consiste à gérer les pics de demande réguliers dans la base de données. Si la base de données est utilisée de façon intensive quotidiennement de 9h à 18h, faites en sorte de pouvoir activer certaines sessions inactives pendant ce laps de temps, car elles seront probablement utiles lors des pics d'activité. Après 18h, vous pouvez laisser Spanner supprimer les sessions inactives. Avant 9h chaque jour, créez de nouvelles sessions afin qu'elles soient prêtes en fonction de la demande attendue.
Un autre scénario consiste à tirer parti d'une application qui utilise Spanner tout en évitant le surcoût de la connexion. Pour ce faire, gardez un ensemble de sessions actif.
Masquer les détails de la session vis-à-vis de l'utilisateur de la bibliothèque cliente
Si vous créez une bibliothèque cliente, n'exposez pas les sessions aux yeux de l'utilisateur de la bibliothèque cliente. Donnez au client la possibilité d'exécuter des appels de base de données sans la complexité liée à la création et à la gestion de sessions. Pour obtenir un exemple de bibliothèque cliente masquant les détails de la session vis-à-vis de ses utilisateurs, consultez la bibliothèque cliente Spanner pour Java.
Traiter les erreurs pour les transactions d'écriture qui ne sont pas idempotentes
Les transactions d'écriture sans protection de réexécution peuvent appliquer des mutations plusieurs fois.
Si une mutation n'est pas idempotente, une mutation appliquée plusieurs fois peut entraîner un échec. Par exemple, une insertion peut échouer et générer une erreur ALREADY_EXISTS
, même si la ligne n'existait pas avant la tentative d'écriture. Cette erreur peut se produire si le serveur backend a validé la mutation, mais est incapable de communiquer la réussite de l'opération au client. Dans ce cas, une nouvelle tentative d'exécution de la mutation sera effectuée, ce qui entraînera l'erreur ALREADY_EXISTS
.
Voici différentes manières de résoudre ce scénario lorsque vous mettez en œuvre votre propre bibliothèque cliente ou utilisez l'API REST :
- Structurez votre écriture pour qu'elle soit idempotente.
- Utilisez les écritures avec protection de réexécution.
- Mettez en œuvre une méthode qui exécute la logique "upsert" : insérer en cas de nouveauté ou mettre à jour l'existant.
- Traitez l'erreur pour le compte du client.
Maintenir des connexions stables
Pour des performances optimales, la connexion que vous utilisez pour héberger une session doit rester stable. Lorsque la connexion qui héberge une session change, Spanner peut supprimer la transaction active sur la session et entraîner une légère charge supplémentaire sur votre base de données pendant la mise à jour des métadonnées de la session. Pas de problème si certaines connexions changent de façon sporadique, mais évitez les situations qui entraîneraient la modification d'un grand nombre de connexions simultanément. Si vous utilisez un proxy entre le client et Spanner, vous devez maintenir la stabilité de la connexion pour chaque session.
Surveiller les sessions actives
Vous pouvez utiliser la commande ListSessions
pour surveiller les sessions actives dans votre base de données à partir de la ligne de commande, avec l'API REST ou avec l'API RPC.
ListSessions
affiche les sessions actives d'une base de données spécifique. Cette fonction est utile si vous avez besoin de trouver la cause d'une fuite de session. (Une fuite de session est un incident au cours duquel des sessions sont en cours de création, mais ne sont pas renvoyées dans un pool de sessions pour être réutilisées.)
ListSessions
vous permet d'afficher des métadonnées sur vos sessions actives, y compris l'heure de création et de dernière utilisation. L'analyse de ces données vous orientera dans la bonne direction lors du dépannage des sessions. Si la plupart des sessions actives ne comportent pas d'indication approximate_last_use_time
récente, cela peut vouloir dire que les sessions ne sont pas réutilisées correctement par votre application. Pour en savoir plus sur le champ approximate_last_use_time
, consultez la documentation de référence de l'API RPC.
Pour en savoir plus sur l'utilisation de ListSessions
, consultez la documentation de référence de l'API REST, de l'API RPC ou de l'outil de ligne de commande gcloud.
Nettoyage automatique des fuites de session
Lorsque vous utilisez toutes les sessions de votre pool de sessions, chaque nouvelle transaction attend qu'une session soit renvoyée dans le pool. Lorsqu'une session est créée, mais qu'elle n'est pas renvoyée dans le pool de sessions pour être réutilisée, on parle de fuite de session. En cas de fuite de session, les transactions en attente d'une session ouverte restent bloquées indéfiniment et bloquent l'application. Les fuites de session sont souvent causées par des transactions problématiques qui s'exécutent pendant une durée extrêmement longue et qui ne sont pas validées.
Vous pouvez configurer votre pool de sessions pour qu'il résolve automatiquement ces transactions inactives. Lorsque vous activez la résolution automatique de la transition inactive dans votre bibliothèque cliente, elle identifie les transactions problématiques susceptibles de provoquer une fuite de session, les supprime du pool de sessions et les remplace par une nouvelle session.
La journalisation peut également vous aider à identifier ces transactions problématiques. Si la journalisation est activée, les journaux d'avertissement sont partagés par défaut lorsque plus de 95% de votre pool de sessions est utilisé. Si l'utilisation de votre session est supérieure à 95%, vous devez soit augmenter le nombre maximal de sessions autorisées dans votre pool de sessions, soit vous faire face à une fuite de session. Les journaux d'avertissement contiennent des traces de pile des transactions qui s'exécutent plus longtemps que prévu et peuvent aider à identifier la cause d'une utilisation élevée du pool de sessions. Les journaux d'avertissement sont transférés en fonction de la configuration de votre exportateur de journaux.
Activer la bibliothèque cliente pour résoudre automatiquement les transactions inactives
Vous pouvez autoriser la bibliothèque cliente à envoyer des journaux d'avertissement et à résoudre automatiquement les transactions inactives, ou à ne recevoir que des journaux d'avertissement.
Java
Pour recevoir des journaux d'avertissement et supprimer les transactions inactives, utilisez setWarnAndCloseIfInactiveTransactions
.
final SessionPoolOptions sessionPoolOptions = SessionPoolOptions.newBuilder().setWarnAndCloseIfInactiveTransactions().build()
final Spanner spanner =
SpannerOptions.newBuilder()
.setSessionPoolOption(sessionPoolOptions)
.build()
.getService();
final DatabaseClient client = spanner.getDatabaseClient(databaseId);
Pour recevoir uniquement les journaux d'avertissement, utilisez setWarnIfInactiveTransactions
.
final SessionPoolOptions sessionPoolOptions = SessionPoolOptions.newBuilder().setWarnIfInactiveTransactions().build()
final Spanner spanner =
SpannerOptions.newBuilder()
.setSessionPoolOption(sessionPoolOptions)
.build()
.getService();
final DatabaseClient client = spanner.getDatabaseClient(databaseId);
Go
Pour recevoir des journaux d'avertissement et supprimer les transactions inactives, utilisez SessionPoolConfig
avec 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()
Pour recevoir uniquement les journaux d'avertissement, utilisez 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)
Sessions multiplexées
Les sessions multiplexées vous permettent de créer un nombre illimité de requêtes simultanées à la fois. Les sessions multiplexées présentent les avantages suivants:
- Réduction des besoins en ressources backend Par exemple, ils évitent les activités de maintenance de session associées à la maintenance de la propriété de la session et à la collecte des déchets.
- Session longue durée qui ne nécessite pas de requêtes de maintien en vie lorsqu'elle est inactive.
- Les bibliothèques clientes standards peuvent utiliser une session multiplexée pour chaque client. Le nombre de sessions régulières utilisées est inférieur pour les clients qui utilisent des sessions multiplexées pour certaines opérations par rapport aux clients qui n'utilisent que des sessions régulières.
- Il n'est pas nécessaire d'avoir une affinité avec un seul canal gRPC. Les clients peuvent envoyer des requêtes via plusieurs canaux pour la même session multiplexée.
Les sessions multiplexées sont compatibles avec les éléments suivants:
- Les bibliothèques clientes Java et Go
- Outils de l'écosystème Spanner qui dépendent des bibliothèques clientes Java et Go, tels que PGAdapter, JDBC, Hibernate, le pilote database/sql et GORM.
- API Spanner pour les transactions en lecture seule
Vous utilisez les métriques OpenTelemetry pour voir comment le trafic est réparti entre le pool de sessions existant et la session multiplexée. OpenTelemetry dispose d'un filtre de métrique, is_multiplexed
, qui affiche les sessions multiplexées lorsqu'il est défini sur true
.
Les sessions multiplexées sont activées par défaut pour l'adaptateur JDBC et PG. Pour les bibliothèques clientes Java et Go, il est désactivé par défaut. Vous utilisez la bibliothèque cliente Java ou la bibliothèque cliente Go pour activer les sessions multiplexées. Pour activer une session multiplexée à l'aide de Java ou de Go, consultez la section Activer les sessions multiplexées.
Activer les sessions multiplexées
Pour activer les sessions multiplexées à l'aide du client Java ou Go, définissez GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS
sur true
.
export GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS=TRUE
Afficher le trafic pour les sessions régulières et multiplexées
Opentelemetry dispose du filtre is_multiplexed
pour afficher le trafic des sessions multiplexées. Définissez ce filtre sur true to view multiplexed sessions
and
false` pour afficher les sessions régulières.
- Configurez OpenTelemetry pour Spanner en suivant les procédures décrites dans la section Avant de commencer de la documentation OpenTelemetry pour Spanner.
Accédez à l'explorateur de métriques.
Dans la liste déroulante Métrique, filtrez sur
generic
.Cliquez sur Tâche générique, puis accédez à Spanner > Spanner/num_acquired_sessions.
Dans le champ Filtre, sélectionnez l'une des options suivantes:
a.
is_multiplexed = false
pour afficher les sessions régulières. b.is_multiplexed = true
pour afficher les sessions multiplexées.L'image suivante montre l'option Filtrer avec les sessions multiplexées sélectionnées.
Pour en savoir plus sur l'utilisation d'OpenTelemetry avec Spanner, consultez les articles Tirer parti d'OpenTelemetry pour démocratiser l'observabilité Spanner et Examiner la latence dans un composant Spanner avec OpenTelemetry.