Comments (16)
And then I can safely call ConnectionPool pool = new ConnectionPool(configuration);
from reactor-pool.
@petromir as discussed in the r2dbc-pool issue, without activity on the pool you need background eviction enabled for it to dispose of idle objects that don't pass the eviction predicate anymore. so this needs to be implemented in r2dbc-pool
directly (which should be easy to contribute).
from reactor-pool.
@simonbasle Thanks for your reply!
Unfortunately using background eviction doesn't help to close the actual connection, just making pool statistics look right.
The issue is easy to reproduce:
- Clone my version of r2dbc-pool with added support for background eviction.
- Run
mvn clean install -DskipTests
- Clone https://github.com/petromir/r2dbc-pool-idle-connection-issue and follow the steps defined in the repository.
As a result we have JMX statistics looking good (with 0 idle connection), BUT still 10 database connections in idle state.
select state, count(pid), query FROM pg_stat_activity where datname = 'books' and pid<>pg_backend_pid() and application_name = 'r2dbc-postgresql' group by state, query;
state | count | query |
---|---|---|
idle | 10 | INSERT INTO book (title, author) VALUES ($1, $2) RETURNING * |
Am I missing something?
I've noticed that there is .releaseHandler(Connection::close)
which results in two exceptions
Caused by: java.lang.IllegalStateException: The connection is closed
This seems to ber2dbc-pool
specific as we have assertion whetherio.r2dbc.pool.PooledConnection
is closed in several places
private void assertNotClosed() {
if (this.closed) {
throw new IllegalStateException("The connection is closed");
}
}
- Inability to acquire a connection.
java.util.concurrent.TimeoutException: Did not observe any item or terminal signal within 7000ms in 'Connection Acquisition from [ConnectionPool[PostgreSQL]]' (and no fallback has been configured)
from reactor-pool.
I see that in your fork you've enabled background eviction but also switched from a releaseHandler
to a destroyHandler
for Connection::close
. Can you confirm that if assertNotClosed
exception is caught and turned into a Mono.error
in that destroyHandler
function, it improves the situation?
from reactor-pool.
(there might indeed be an issue with destroyHandler
s that throw from the Function
instead of returning a Mono.error
. reopening)
from reactor-pool.
@simonbasle The only thing that I have done in my version is adding of .evictInBackground(maxIdleTime)
during pool construction. See original version vs. mine
It will take a bit more time until I convert all the invocations of assertNotClosed
to Mono<Void>
.
from reactor-pool.
@petromir Can you verify latest snapshots (from the merge of #139) with your r2dbc-pool fork and validate it fixes your reproduction case?
from reactor-pool.
@simonbasle when 0.2.5
will be available in Maven Central?
from reactor-pool.
@simonbasle when
0.2.5
will be available in Maven Central?
Next tuesday (updated the milestones). If you could verify the fix using snapshots today, that would be perfect.
from reactor-pool.
I will do my best π
from reactor-pool.
I had some time to investigate, and despite the changes I've made I was still seeing 10 idle connections... Then something felt off, so I tried playing around with the configuration of the pool in the app.
I've set the maximum size to 5
and wrapping the ConnectionFactory
so that create()
calls could be counted. And indeed, the application makes less than 5 calls to create()
...
But still, pg tells me that there are 10 idle connections π€
And then I noticed that ConnectionPoolConfiguration#build
from r2dbc-pool is called twice... and the first time it uses default values for minSize
and maxSize
, which happens to be 10 !
So it hit me: you're configuring a pool around a pool:
final ConnectionFactory connectionFactory = ConnectionFactories.get(ConnectionFactoryOptions.builder()
.option(DRIVER, "pool")
.option(PROTOCOL, "postgresql")
The logs even plainly warn you about it at the start of the application !! π€¦ββοΈ
WARN 53028 --- [ main] io.r2dbc.pool.ConnectionPool : Creating ConnectionPool using another ConnectionPool [ConnectionPool[PostgreSQL]] as ConnectionFactory
Using the postgresql driver directly as basis for the r2dbc-pool, with background eviction, correctly makes these idle connections disappear from pg's perspective.
from reactor-pool.
Didn't get what is wrong with the pool configuration as the example in r2dbc-pool was used as a source
ConnectionFactory connectionFactory = ConnectionFactories.get(ConnectionFactoryOptions.builder()
.option(DRIVER, "pool")
.option(PROTOCOL, "postgresql") // driver identifier, PROTOCOL is delegated as DRIVER by the pool.
.option(HOST, "β¦")
.option(PORT, "β¦")
.option(USER, "β¦")
.option(PASSWORD, "β¦")
.option(DATABASE, "β¦")
.build());
from reactor-pool.
@petromir you're mixing two methods of creating ConnectionPool
s: discovery with options and full programmatic builder-based creation.
This creates 3 ConnectionFactory
:
- discovery via
ConnectionFactories.get(...).build()
creates aConnectionPool
(DRIVER = pool), which is aConnectionFactory
- it also creates (and wraps over) a postgresql
ConnectionFactory
(PROTOCOL = postgresql) new ConnectionPool(configuration)
explicitly creates aConnectionPool
wrapping over (1) which itself wraps over (2).
(1) is created with default configuration (because no particular pool-related option(...)
have been set other than the PROTOCOL). This amounts to minSize = 10
and no background eviction.
(3) is the outer pool, and is indeed configured with background eviction and minSize 0 this time.
As soon as a connection is requested from that second pool, it will hit the inner pool which will warm up 10 connections and attempts to keep them around (minSize = 10), despite the outer pool being configured for background eviction and minSize 0.
from reactor-pool.
Well this seems to be quite confusing for users of r2dbc-pool
as configuring the pool programmatically is exactly in the way I did it
ConnectionFactory connectionFactory = β¦;
ConnectionPoolConfiguration configuration = ConnectionPoolConfiguration.builder(connectionFactory)
.maxIdleTime(Duration.ofMillis(1000))
.maxSize(20)
.build();
ConnectionPool pool = new ConnectionPool(configuration);
What should be the right way to combine both settings, so that we don't have several connection pools created?
from reactor-pool.
I don't think the intention was for these ...
to represent a ConnectionPool
instantiation.
Rather, it should be the typical instantiation code for whichever plain driver you want/need underneath the pool, in that case postgresql
.
Simplest way to fix your sample is to have the discovery instantiation directly discover postgresql connection factory:
final ConnectionFactory connectionFactory = ConnectionFactories.get(ConnectionFactoryOptions.builder()
.option(DRIVER, "postgresql") //postgres is the DRIVER now, removing the need for PROTOCOL
//the rest stays as is
.option(PORT, port)
.option(HOST, "localhost")
.option(USER, "root")
.option(PASSWORD, "password")
.option(DATABASE, "books")
.option(Option.valueOf("preparedStatementCacheQueries"), 0)
.build());
//here everything stays the same since now `connectionFactory` is not a pooled one
final ConnectionPoolConfiguration configuration = ConnectionPoolConfiguration.builder(connectionFactory)
.initialSize(0)
.maxSize(20)
.maxIdleTime(Duration.ofMillis(2500))
.maxCreateConnectionTime(Duration.ofSeconds(10))
.acquireRetry(3)
.maxAcquireTime(Duration.ofSeconds(7))
.registerJmx(true)
.name("r2dbc")
.build();
from reactor-pool.
@simonbasle I've tested with the snapshot locally and I can confirm that everything works as expected, but only with the DRIVER
trick. Thanks a lot!
from reactor-pool.
Related Issues (20)
- maxPending limit is enforced with some de-facto leniency under heavy load HOT 4
- Possible pool resource release bug HOT 11
- Suppress CommonPoolTest#pendingLimitAsync(Function) onErrorDropped logging
- PoolMetrics.acquiredSize() is incremented too early HOT 1
- Missing SimpleDequePool.drain() when SimpleDequePool.cancelAcquire() HOT 1
- InstrumentedPool: better insights into pool inactivity HOT 1
- Remove outdated issue template and Contributing.md
- Wrong pool metrics when invalidating an idle resource HOT 4
- Quiet period & timeout wait for waiting requests and active connections HOT 4
- Performance issue in SimpleDequePool class
- Soft eviction for in-use connections
- when I use spring cloud gatawayοΌI find reactor.netty.internal.shaded.reactor.pool.AbstractPool.Borrower#request use a lot of cpu HOT 1
- Provide Micrometer PoolMetricsRecorder adapter HOT 3
- Add support to pool to do scheduled connection validation HOT 11
- Problems when warmup procedure and database query procedure running in parallel.
- `PoolMetrics.allocatedSize` reports a different allocation count when the allocator uses threads HOT 4
- Incorrect handling of allocator errors during "warmup" in SimpleDequePool HOT 1
- InstrumentedPool.PoolMetrics isInactiveForMoreThan mixes time units HOT 3
- Warmup procedure fails if warmups were found HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from reactor-pool.