Sessions

This page describes the advanced concept of sessions in Spanner,including best practices for sessions when creating a client library,using the REST or RPC APIs, or using the Google client libraries.

A session represents a communication channel with the Spannerdatabase service. A session is used to perform transactions that read, write, ormodify data in a Spanner database. Each session applies to asingle database.

Sessions can execute a single or multipletransactions at a time. Whenperforming multiple transactions, the session is called amultiplexed session.Standalone reads, writes, and queries use one transaction internally.

Performance benefits of a session pool

Creating a session is expensive. To avoid the performance cost each time adatabase operation is made, clients should keep asession pool, which is a poolof available sessions that are ready to use. The pool should store existing sessionsand return the appropriate type of session when requested, as well as handle cleanupof unused sessions. For an example of how to implement a session pool, see thesource code for one of the Spanner client libraries, such as theGo client library or theJava client library.

Sessions are intended to be long-lived, so after a session is used for adatabase operation, the client should return the session to the pool for reuse.

Overview of gRPC channels

gRPC channels are used by the Spanner client for communication. One gRPCchannel is roughly equivalent to a TCP connection. One gRPC channel can handleup to 100 concurrent requests. This means that an application will need at leastas many gRPC channels as the number of concurrent requests the application willexecute, divided by 100.

The Spanner client creates a pool of gRPC channels when youcreate it.

Best practices when using Google client libraries

The following describes best practices when using the Googleclient libraries for Spanner.

Configure the number of sessions and gRPC channels in the pools

The client libraries have a default number of sessions in the session pool and adefault number of gRPC channels in the channel pool. Both defaults are adequatefor most cases. The following are the default minimum and maximum sessions andthe default number of gRPC channels for each programming language.

C++

MinSessions:100MaxSessions:400NumChannels:4

C#

MinSessions:100MaxSessions:400NumChannels:4

Go

MinSessions:100MaxSessions:400NumChannels:4

Java

MinSessions:100MaxSessions:400NumChannels:4

Node.js

The Node.js client does not support multiple gRPC channels. It is thereforerecommended to create multiple clients instead of increasing the size of thesession pool beyond 100 sessions for a single client.

MinSessions:25MaxSessions:100

PHP

The PHP client does not support a configurable number of gRPC channels.

MinSessions: 1MaxSessions: 500

Python

Python supports four differentsession pool typesthat you can use to manage sessions.

Ruby

The Ruby client does not support multiple gRPC channels. It is thereforerecommended to create multiple clients instead of increasing the size of thesession pool beyond 100 sessions for a single client.

MinSessions:10MaxSessions:100

The number of sessions that your application uses is equal to the number ofconcurrent transactions that your application executes. You should modify thedefault session pool settings only if you expect a single application instanceto execute more concurrent transactions than the default session pool canhandle.

For high concurrency applications the following is recommended:

  1. SetMinSessions to the expected number of concurrent transactions that asingle client will execute.
  2. SetMaxSessions to the maximum number of concurrent transactions that asingle client can execute.
  3. SetMinSessions=MaxSessions if the expected concurrency does not changemuch during the application lifetime. This prevents the session pool fromscaling up or down. Scaling the session pool up or down also consumes someresources.
  4. SetNumChannels toMaxSessions / 100. One gRPC channel can handle up to100 requests concurrently. Increase this value if you observe a high taillatency (p95/p99 latency), because this could be an indication of gRPCchannel congestion.

Increasing the number of active sessions uses additional resources on theSpanner database service and in the client library. Increasing thenumber of sessions beyond the actual need of the application could degrade theperformance of your system.

Increase the session pool versus increasing the number of clients

The session pool size for an application determines how many concurrenttransactions a single application instance can execute. Increasing the sessionpool size beyond the maximum concurrency that a single application instance canhandle is not recommended. If the application receives a burst of requeststhat goes beyond the number of sessions in the pool, the requests are queuedwhile waiting for a session to become available.

The resources that are consumed by the client library are the following:

  1. Each gRPC channel uses one TCP connection.
  2. Each gRPC invocation requires a thread. The maximum number ofthreads that is used by the client library is equal to the maximum number ofconcurrent queries that the application executes. These threads come on topof any threads that the application uses for its own business logic.

Increasing the size of the session pool beyond the maximum number of threadsthat a single application instance can handle is not recommended. Instead,increase the number of application instances.

Manage the write-sessions fraction

For some client libraries, Spanner reserves a portion of the sessionsfor read-write transactions, called the write-sessions fraction. If your appuses up all the read sessions, then Spanner uses the read-writesessions, even for read-only transactions. Read-write sessions requirespanner.databases.beginOrRollbackReadWriteTransaction. If the user is in thespanner.databaseReader IAM role, then the call failsand Spanner returns this error message:

generic::permission_denied: Resource %resource% is missing IAM permission:spanner.databases.beginOrRollbackReadWriteTransaction

For the client libraries that maintain a write-sessions fraction, you can setthe write-sessions fraction.

C++

All C++ sessions are the same. There are no read or read-write onlysessions.

C#

The default write-sessions fraction for C# is 0.2. You can change thefraction using the WriteSessionsFraction field ofSessionPoolOptions.

Go

All Go sessions are the same. There are no read or read-write only sessions.

Java

All Java sessions are the same. There are no read or read-write onlysessions.

Node.js

All Node.js sessions are the same. There are no read or read-write onlysessions.

PHP

All PHP sessions are the same. There are no read or read-write onlysessions.

Python

Python supports four differentsession pool typesthat you can use to manage read and read-write sessions.

Ruby

The default write-sessions fraction for Ruby is 0.3. You can change thefraction using theclientinitialize method.

Best practices when creating a client library or using REST/RPC

The following describes best practices for implementing sessions in a clientlibrary for Spanner, or for using sessions with theREST orRPC APIs.

These best practices only apply if you aredeveloping a client library, or ifyou are using REST/RPC APIs. If you are using one of the Google clientlibraries for Spanner, refer toBest practices when using Google client libraries.

Create and size the session pool

To determine an optimal size of the session pool for a client process, set thelower bound to the number of expected concurrent transactions, and set the upperbound to an initial test number, such as 100. If the upper bound is not adequate,increase it. Increasing the number of active sessions uses additional resourceson the Spanner database service, so failing to clean up unused sessionscan degrade performance. For users working with the RPC API, we recommend havingno more than 100 sessions per gRPC channel.

Handle deleted sessions

There are three ways to delete a session:

  • A client can delete a session.
  • The Spanner database service can delete a session when the session isidle for more than 1 hour.
  • The Spanner database service may delete a session if the session ismore than 28 days old.

Attempts to use a deleted session result inNOT_FOUND. If you encounterthis error, create and use a new session, add the new session to the pool, andremove the deleted session from the pool.

Keep an idle session alive

The Spanner database service reserves the right to drop an unusedsession. If you definitely need to keep an idle session alive, for example, if asignificant near-term increase in database use is expected, then you can preventthe session from being dropped. Perform an inexpensive operation such asexecuting the SQL querySELECT 1 to keep the session alive. If you have anidle session that is not needed for near-term use, let Spanner drop thesession, and then create a new session the next time a session is needed.

One scenario for keeping sessions alive is to handle regular peak demand on thedatabase. If heavy database use occurs daily from 9:00 AM to 6:00 PM, youshould keep some idle sessions alive during that time, since they are likelyrequired for the peak usage. After 6:00 PM, you can let Spanner dropidle sessions. Prior to 9:00 AM each day, create some new sessions so they willbe ready for the expected demand.

Another scenario is if you have an application that uses Spanner butmust avoid the connection overhead when it does. You can keep a set of sessionsalive to avoid the connection overhead.

Hide session details from the client library user

If you are creating a client library, don't expose sessions to the clientlibrary consumer. Provide the ability for the client to make database callswithout the complexity of creating and maintaining sessions. For an example of aclient library that hides the session details from the client library consumer,see the Spanner client library for Java.

Handle errors for write transactions that are not idempotent

Write transactions without replay protection may apply mutations more than once.If a mutation is not idempotent, a mutation that is applied more than once couldresult in a failure. For example, an insert may fail withALREADY_EXISTS even though the row did not exist prior to thewrite attempt. This could occur if the backend server committed the mutation butwas unable to communicate the success to the client. In that event, the mutationcould be retried, resulting in theALREADY_EXISTS failure.

Here are possible ways to address this scenario when you implement your ownclient library or use the REST API:

  • Structure your writes to be idempotent.
  • Use writes with replay protection.
  • Implement a method that performs "upsert" logic: insert if new or update ifexists.
  • Handle the error on behalf of the client.

Maintain stable connections

For best performance, the connection that you use to host a session shouldremain stable. When the connection that hosts a session changes, Spannermight abort the active transaction on the session and cause a small amount ofextra load on your database while it updates the session metadata. It is OK ifa few connections change sporadically, but you should avoid situations thatwould change a large number of connections at the same time. If you use a proxybetween the client and Spanner, you should maintain connection stabilityfor each session.

Monitor active sessions

You can use theListSessions command to monitor active sessions in yourdatabase from thecommand line, withthe REST API, or withthe RPCAPI.ListSessions shows the active sessions for a given database. This isuseful if you need to find the cause of a session leak. (A session leak is anincident where sessions are being created but not returned to a session pool forreuse.)

ListSessions lets you view metadata about your active sessions, including whena session was created and when a session was last used. Analyzing this data willpoint you in the right direction when troubleshooting sessions. If most activesessions don't have a recentapproximate_last_use_time, this could indicatethat sessions aren't being reused properly by your application. See theRPC APIreference for more information about theapproximate_last_use_time field.

See theREST API reference, theRPC API reference, or thegcloudcommand-line tool reference for more information on usingListSessions.

Automatic cleanup of session leaks

Preview —Automatic cleanup of session leaks

This feature is subject to the "Pre-GA Offerings Terms" in the General Service Terms section of theService Specific Terms. Pre-GA features are available "as is" and might have limited support. For more information, see thelaunch stage descriptions.

When you use all the sessions in your session pool, each new transactionwaits until a session is returned to the pool. When sessions are createdbut not returned to the session pool for reuse, this is called a session leak.When there is a session leak, transactions waiting for an open session get stuckindefinitely and block the application. Session leaks are often caused byproblematic transactions that are running for an extremely long time andaren't committed.

You can setup your session pool to automatically resolve theseinactive transactions. When you enable your client library to automaticallyresolve inactive transition, it identifies problematic transactions thatmight cause a session leak, removes them from the session pool, andreplaces them with a new session.

Logging can also help identify these problematic transactions.If logging is enabled, warning logs are shared by default when more than95% of your session pool is in use. If your session usage is greater than 95%,then you either need to increase the max sessions allowed in your session pool,or you might have a session leak. Warning logs contain stacktraces of transactions that run for longer than expected and canhelp identify the cause of high session pool utilization.Warning logs are pushed depending on your log exporter configuration.

Enable client library to automatically resolve inactive transactions

You can either enable client library to send warning logs and automaticallyresolve inactive transactions, or enable client library to only receive warninglogs.

Java

To receive warning logs and remove inactive transactions, usesetWarnAndCloseIfInactiveTransactions.

finalSessionPoolOptionssessionPoolOptions=SessionPoolOptions.newBuilder().setWarnAndCloseIfInactiveTransactions().build()finalSpannerspanner=SpannerOptions.newBuilder().setSessionPoolOption(sessionPoolOptions).build().getService();finalDatabaseClientclient=spanner.getDatabaseClient(databaseId);

To only receive warning logs, usesetWarnIfInactiveTransactions.

finalSessionPoolOptionssessionPoolOptions=SessionPoolOptions.newBuilder().setWarnIfInactiveTransactions().build()finalSpannerspanner=SpannerOptions.newBuilder().setSessionPoolOption(sessionPoolOptions).build().getService();finalDatabaseClientclient=spanner.getDatabaseClient(databaseId);

Go

To receive warning logs and remove inactive transactions, useSessionPoolConfig withInactiveTransactionRemovalOptions.

client,err:=spanner.NewClientWithConfig(ctx,database,spanner.ClientConfig{SessionPoolConfig:spanner.SessionPoolConfig{InactiveTransactionRemovalOptions:spanner.InactiveTransactionRemovalOptions{ActionOnInactiveTransaction:spanner.WarnAndClose,}}},)iferr!=nil{returnerr}deferclient.Close()

To only receive warning logs, usecustomLogger.

customLogger:=log.New(os.Stdout,"spanner-client: ",log.Lshortfile)// Create a logger instance using the golang log packagecfg:=spanner.ClientConfig{Logger:customLogger,}client,err:=spanner.NewClientWithConfig(ctx,db,cfg)

Multiplexed sessions

Multiplexed sessions let you create a large number of concurrent requestson a single session. A multiplexed session is an identifier that youuse across multiple gRPC channels. It doesn't introduce any additionalbottlenecks. Multiplexed sessions have the following advantages:

  • Reduced backend resource consumption due to a more straightforward sessionmanagement protocol. For example, they avoid session maintenance activitiesassociated with session ownership maintenance and garbage collection.
  • Long-lived session that doesn't require keep-alive requests when idle.

Multiplexed sessions are supported in the following:

  • The C++, Go, Java, Node.js, PHP, Python, and Rubyclient libraries.
  • Spanner ecosystem tools that depend on the mentioned client Libraries,such as PGAdapter, JDBC, Hibernate, database/sql driver, dbAPI driver and GORM.

  • Spanner ecosystem tools that depend on the Java and Go clientLibraries, such as PGAdapter, JDBC, Hibernate, database or sql driver, andGORM.You can useOpenTelemetry metrics to see how traffic is splitbetween the existing session pool and the multiplexed session. OpenTelemetry hasa metric filter,is_multiplexed, that shows multiplexed sessions when set totrue.

Multiplexed sessions are supported for all types of transactions.

Client libraries rotate multiplexed sessions every 7 days to prevent sendingtransactions on stale sessions.

Multiplexed sessions are enabled by default in some client libraries. For others,you must use environment variables to enable them. For details, seeEnable multiplexed sessions.

Considerations

If you're trying to commit either an empty read or write transaction body or atransaction where every query or DML statement has failed, there are a couple ofscenarios to consider with multiplexed sessions. Multiplexed sessions requirethat you include a server-generated pre-commit token in each commit request. Fortransactions that contain queries or DML, there must be at least one previoussuccessful query or DML transaction for the server to send back a valid token tothe client library. If there haven't been any successful queries or DMLtransactions, the client library implicitly addsSELECT 1 before a commit.

For a read or write transaction on a multiplexed session that only hasmutations, if one of the mutations is for a table or acolumn that does NOT exist in the schema, the client could return anINVALID_ARGUMENT error instead of aNOT_FOUND error.

Enable multiplexed sessions

Multiplexed sessions are enabled by default in the following client libraries:

  • C++ in version 2.41.0 and later.
  • Go in version 1.85.0 and later.
  • Java in version 6.98.0 and later.
  • Node.js in version 8.3.0 and later.
  • PHP in version 2.0.0 and later.
  • Python in version 3.57.0 and later.
  • Ruby in version 2.30.0 and later.

To use multiplexed sessions in earlier versions of Node.js,Java and Go client libraries, you must first set an environment variable toenable it.

To enable multiplexed sessions, set theGOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS environment variable toTRUE. Thisflag also enables the multiplexed sessions support forReadOnly transactions.

exportGOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS=TRUE

To enable partitioned operations support for multiplexed sessions, set theGOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_PARTITIONED_OPS environment variabletoTRUE.

exportGOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_PARTITIONED_OPS=TRUE

To enable read-write transactions support for multiplexed sessions, set theGOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_FOR_RW environment variable toTRUE.

exportGOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_FOR_RW=True

You must setGOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS toTRUE as aprerequisite for supporting a transaction on a multiplexed session.

View traffic for regular and multiplexed sessions

OpenTelemetry has theis_multiplexed filter to show the traffic formultiplexed sessions. You set this filter totrue to view multiplexed sessionsandfalse` to view regular sessions.

  1. Set up OpenTelemetry for Spanner using the procedures in theSpanner OpenTelemetryBefore you beginsection.
  2. Navigate to theMetrics Explorer.

    Go to Metrics Explorer

  3. In theMetric drop-down, filter ongeneric.

  4. ClickGeneric Task and navigate toSpanner >Spanner/num_acquired_sessions.

  5. In theFilter field, select from the following options:

    a.is_multiplexed = false to view regular sessions.b.is_multiplexed = true to view multiplexed sessions.

    The following image shows theFilter option with multiplexed sessionsselected.

For more information about using OpenTelemetry with Spanner, seeLeveraging OpenTelemetry to democratize Spanner Observability andExamine latency in a Spanner component with OpenTelemetry.

Opentelemetry dashboard showing the is-multiplexed filter.

Troubleshoot

Common session-related errors that your application might encounter include:

  • Session not found
  • RESOURCE_EXHAUSTED

For more information, seeSession errors.

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2026-02-19 UTC.