Skip to content

perf: use multiplexed sessions#1673

Merged
olavloite merged 2 commits intomainfrom
enable-multiplexed-sessions
Jul 4, 2024
Merged

perf: use multiplexed sessions#1673
olavloite merged 2 commits intomainfrom
enable-multiplexed-sessions

Conversation

@olavloite
Copy link
Collaborator

@olavloite olavloite commented Jul 3, 2024

Enable the use of multiplexed sessions by default for queries in auto-commit mode. Multiplexed sessions can handle any number of queries concurrently. This means that the JDBC driver does not need to check out a session exclusively from the internal session pool in order to execute a query. Instead, a single multiplexed session is enough for all queries that are executed by all JDBC connections that connect to the same Spanner database. This allows a higher degree of parallelism to be achieved from a single client machine.

Note that due to how the JDBC API is defined, each JDBC connection can only execute one query at a time. If you for example want to execute 1000 queries in parallel, then you also need to create 1000 JDBC connections. Spanner JDBC connection are however lightweight, as each JDBC connection internally uses a pool of gRPC channels.

A high degree of parallelism from a single client might require a higher number of gRPC channels than the default 4. You can set a higher number of gRPC channels with the JDBC connection URL option numChannels, e.g. numChannels=8.

It is also recommended to enable the use of virtual threads to achieve the highest possible degree of parallelism with the JDBC driver. This option can be set by adding useVirtualThreads=true to the JDBC connection URL. Note that virtual threads are only supported on Java 21 and higher. Setting this option on a JVM version 20 or lower will have no effect, and the JDBC driver will instead use platform threads.

Enable the use of multiplexed sessions by default for queries in
auto-commit mode. Multiplexed sessions can handle any number of
queries concurrently. This means that the JDBC driver does not
need to check out a session exclusively from the internal session
pool in order to execute a query. Instead, a single multiplexed
session is enough for all queries that are executed by all JDBC
connections that connect to the same Spanner database. This
allows a higher degree of parallelism to be achieved from a
single client machine.

Note that due to how the JDBC API is defined, each JDBC
connection can only execute one query at a time. If you for
example want to execute 1000 queries in parallel, then you
also need to create 1000 JDBC connections. Spanner JDBC
connection are however lightweight, as each JDBC connection
internally uses a pool of gRPC channels.

It is recommended to enable the use of virtual threads to
achieve the highest possible degree of parallelism with the
JDBC driver. This option can be set by adding useVirtualThreads=true
to the JDBC connection URL. Note that virtual threads are only
supported on Java 21 and higher.
@olavloite olavloite requested a review from a team July 3, 2024 18:13
@product-auto-label product-auto-label bot added size: l Pull request size is large. api: spanner Issues related to the googleapis/java-spanner-jdbc API. labels Jul 3, 2024
@olavloite olavloite requested a review from harshachinta July 3, 2024 18:13
@Test
public void testUsesRegularSessionForQueryInTransaction() throws SQLException {
try (Connection connection = createConnection()) {
connection.setAutoCommit(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a test to show that when autocommit is set to false, but the transaction is read-only, then the requests use multiplexed sessions?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, done.

@Test
public void testUsesMultiplexedSessionForQueryInReadOnlyTransaction() throws SQLException {
int numQueries = 2;
try (Connection connection = createConnection()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: do we need to explicitly call connection#commit() or does it automatically happen when it comes out of try block?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Closing a connection with an active transaction will automatically commit that transaction, so in this case we could skip the commit() call. It is however not something I would consider good practice, as letting a transaction be implicitly committed makes it harder to read/understand the code.

I would for example normally assume that an active transaction would be rolled back if the connection is closed while the transaction is active, but the JDBC spec requires the driver implementation to commit the transaction. This might not be known to everyone, which again could lead people to believe that the transaction is rolled back instead of committed.

@olavloite olavloite merged commit 107ec66 into main Jul 4, 2024
@olavloite olavloite deleted the enable-multiplexed-sessions branch July 4, 2024 08:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api: spanner Issues related to the googleapis/java-spanner-jdbc API. size: l Pull request size is large.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants