-
Notifications
You must be signed in to change notification settings - Fork 995
Connection Pooling
Lettuce connections are designed to be thread-safe so one connection can be shared amongst multiple threads and lettuce connections auto-reconnection by default. While connection pooling is not necessary in most cases it can be helpful in certain use cases. lettuce provides generic connection pooling support.
Lettuce is thread-safe by design which is sufficient for most cases. All Redis user operations are executed single-threaded. Using multiple connections does not impact the performance of an application in a positive way. The use of blocking operations usually goes hand in hand with worker threads that get their dedicated connection. The use of Redis Transactions is the typical use case for dynamic connection pooling as the number of threads requiring a dedicated connection tends to be dynamic. That said, the requirement for dynamic connection pooling is limited. Connection pooling always comes with a cost of complexity and maintenance.
Lettuce requires Apache’s common-pool2 dependency (at least 2.2) to provide connection pooling. Make sure to include that dependency on your classpath. Otherwise you won’t be able using connection pooling.
If using Maven, add the following dependency to your pom.xml
:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.2</version>
</dependency>
lettuce provides generic connection pool support. It requires a connection Supplier
that is used to create connections of any supported type (Redis Standalone, Pub/Sub, Sentinel, Master/Slave, Redis Cluster). ConnectionPoolSupport
will create a GenericObjectPool
or SoftReferenceObjectPool
, depending on your needs. The pool can allocate either wrapped or direct connections.
-
Wrapped instances will return the connection back to the pool when called
StatefulConnection.close()
. -
Regular connections need to be returned to the pool with
GenericObjectPool.returnObject(…)
.
Basic usage
RedisClient client = RedisClient.create(RedisURI.create(host, port));
GenericObjectPool<StatefulRedisConnection<String, String>> pool = ConnectionPoolSupport
.createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig());
// executing work
try (StatefulRedisConnection<String, String> connection = pool.borrowObject()) {
connection.multi();
connection.set("key", "value");
connection.set("key2", "value2");
connection.exec();
}
// terminating
pool.close();
client.shutdown();
Cluster usage
RedisClusterClient clusterClient = RedisClusterClient.create(RedisURI.create(host, port));
GenericObjectPool<StatefulRedisClusterConnection<String, String>> pool = ConnectionPoolSupport
.createGenericObjectPool(() -> clusterClient.connect(), new GenericObjectPoolConfig());
// executing work
try (StatefulRedisClusterConnection<String, String> connection = pool.borrowObject()) {
connection.sync().set("key", "value");
connection.sync().blpop(10, "list");
}
// terminating
pool.close();
clusterClient.shutdown();
Reactive execution consists of two part: Construction and subscription. Connection pooling affects how you release the borrowed connection back to the pool. Like in a synchronous programming model, you obtain a connection upon construction time to get a handle for Publisher
creation. I
n a synchronous programming model, you would release the connection immediately once you’re done with the call. That’s different for reactive programming: You need to retain the connection until the actual execution is terminated and then release the connection back to the pool. Eager release keeps reference to the connection in the reactive sequence and release the connection back to the pool. Any other thread then can borrow the same connection and run into false sharing issues.
Reactive usage example
RedisClient client = RedisClient.create(RedisURI.create(host, port));
GenericObjectPool<StatefulRedisConnection<String, String>> pool = ConnectionPoolSupport
.createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig());
// executing work
StatefulRedisConnection<String, String> connection = pool.borrowObject();
Mono<String> result = connection.reactive().set("key", "value")
.then(connection.reactive().get("key"))
.doOnTerminate((s, throwable) -> connection.close());
// execute & synchronize result
// terminating
pool.close();
client.shutdown();
lettuce provides connection pooling for Redis Standalone and Redis Sentinel-managed connections. The connection pool allows to create connections and use them as you require. Used connections can be returned to the pool and can be reused. Connection pooling is available for sync and async APIs.
Basic usage
RedisConnectionPool<RedisConnection<String, String>> pool = client.pool();
try (RedisConnection<String, String> connection = pool.allocateConnection()) {
connection.multi();
connection.set("key", "value");
connection.set("key2", "value2");
connection.exec();
}
// when terminating
pool.close();
Async usage
RedisConnectionPool<RedisAsyncConnection<String, String>> pool = client.asyncPool();
try (RedisConnection<String, String> connection = pool.allocateConnection()) {
connection.multi();
connection.set("key", "value");
connection.set("key2", "value2");
connection.exec().get();
}
// when terminating
pool.close();
Pooled connections implement AutoCloseable
to support try-with-resources notion. Calling close()
on a pooled instance will redirect the call to release the connection back to the pool. Pooled connections are only useful if:
-
You use blocking calls such as
BLPOP
,BRPOP
, … to not block the whole connection. Once a connection is blocked by a blocking command, it will stay in this state until Redis responds with the result -
You use transactions (
MULTI
/EXEC
). Transactions will switch your connection in a transactional state. Other threads which share the connection would fall unintentionally into the transaction.
The connection pool can be configured with maxIdle
and maxActive
parameters which default to 5
and 20
.
Lettuce documentation was moved to https://redis.github.io/lettuce/overview/
Intro
Getting started
- Getting started
- Redis URI and connection details
- Basic usage
- Asynchronous API
- Reactive API
- Publish/Subscribe
- Transactions/Multi
- Scripting and Functions
- Redis Command Interfaces
- FAQ
HA and Sharding
Advanced usage
- Configuring Client resources
- Client Options
- Dynamic Command Interfaces
- SSL Connections
- Native Transports
- Unix Domain Sockets
- Streaming API
- Events
- Command Latency Metrics
- Tracing
- Stateful Connections
- Pipelining/Flushing
- Connection Pooling
- Graal Native Image
- Custom commands
Integration and Extension
Internals