-
Notifications
You must be signed in to change notification settings - Fork 312
Add a span when waiting for an available database connection from a pool #9251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
df910b9
to
fec7eac
Compare
Also: see support case 2199108 |
Thanks for the contribution @deejgregor! |
I've done a little bit more experimenting and I've found a few things along the way, so I wanted to provide an update and ask a few questions. First, my update: I simplified (I think) My questions:
Configuration options and tracingTodayjdbc-datasource not enabled (default)Database pool and database driver connection operations are not visible: no jdbc-datasource enabled
FutureI wanted to propose an option or two of how to configure this, but I haven't been terribly happy with anything I came up with. Here are my main thoughts:
That combination gets me three things:
One option could be to just enable the |
9515216
to
a9a65c0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, let me check your latest improvements...
Thanks a lot for this contribution - the pool.waiting span is a very valuable addition and helps explain connection pool exhaustion delays much more clearly. A few comments:
I really like your vision for future improvements - especially the idea of adding more pool-level metrics (e.g. provider, max size, active usage). That would make the traces much more insightful. I also share your concern about generating a large number of short spans in high-traffic systems. Sampling or aggregating metrics instead of emitting every single pool.waiting span could be a good direction. One question for you: do you prefer to merge the current changes as they are (so we can start getting value from |
- Use dd.trace.experimental.jdbc.pool.waiting.enabled=true to enable. - Change instrumentation name from jdbc-datasource to jdbc. - Record exceptions. - Use default instrumentation name (jdbc). - Set resource name to {dbcp2,hikari}.waiting
Also add PoolWaitingDecorator.
a9a65c0
to
b5e714a
Compare
I just pushed updates that I think should address the first two items below.
Done.
Done.
Good news!
The more that I think of it, I've gotten to be pretty unconcerned about creating |
What Does This Do
This adds a
pool.waiting
span when waiting for an available database connection from a Hikari (>= 2.4.0) or DBCP2 (>= 2.10.0) connection pool.Motivation
Additional Notes
Is this a contribution you would be interested in?
It would definitely be helpful to us at $WORK if this could be in the tracer, as we use connection pools heavily and delays due to exhausted connection pools tend to be not be quick to identify.
Concerns
For modern versions of HIkari, the instrumentation to determine blocking in
HikariBlockedTrackingSynchronousQueue
replaces theSynchronousQueue
created byConcurrentBag.<init>
, and assumes thattrue
is always passed when creating theSynchronousQueue
. This sets the fairness policy and it has been set this way since 2017, so the likelihood of it changing in future versions of HIkari is very low.Instrumented Code
Hikari
There is a common method,
ConcurrentBag.borrow
, that is used for both blocking and non-blocking paths. This method is instrumented along with deeper methods that indicate when the blocking path was taken. Depending on the Hikari version, there are two different downstream methods that are instrumented. AThreadLocal
is used with the help ofHikariBlockedTracker
to communicate between the various instrumentations when the blocking path was taken. Apool.waiting
span is created whenConcurrentBag.borrow
returns, but only if blocking occurred.Apache DBCP2
In commons-pool >= 2.10.0 and later, this is straightforward, as
LinkedBlockingDeque.pollFirst(Duration)
is called only in blocking cases byGenericObjectPool.borrowObject
from a number of places in dbcp2. ACallDepthThreadLocalMap
is used to ensure a span is only created whenLinkedBlockingDeque.pollFirst
is called from dbcp2 and a test method is added toJDBCInstrumentationTestBase
to ensure this is the case.This code can be extended to work with earlier versions of commons-pool, however determining the blocking signature of
poolFirst
will require a little bit more work and might require differentiating between versions of commons-pool to make sure only the appropriate signature is instrumented (or looking for another way to determine blocking).Test cases
A test method was added in
JDBCInstrumentationTestBase
.Additional work
Although this seems to work functionally in with the included test, there are a few items still being worked on:
Other considerations
getConnection()
calls to database drivers be traced from connection pools to indicate when a request delay is caused by new connection is being opened? This might be particularly helpful for forking database backends like PostgreSQL that have longer connection times.Contributor Checklist
type:
and (comp:
orinst:
) labels in addition to any usefull labelsclose
,fix
or any linking keywords when referencing an issue.Use
solves
instead, and assign the PR milestone to the issueJira ticket: [PROJ-IDENT]