Skip the client response-time Observation when no tracing is configured - #4328
Open
samueldlightfoot wants to merge 2 commits into
Open
samueldlightfoot wants to merge 2 commits into
samueldlightfoot wants to merge 2 commits into
Conversation
Contributor
Author
|
@violetagg keen for your thoughts on this. It could be a big win out of the box for those wanting metrics with no use for observations. |
When HTTP client metrics are enabled but no tracing consumer is registered, the built-in Micrometer recorder still ran a full per-request Observation solely to record the response-time timer, allocating a per-request ConcurrentHashMap, Timer.Sample and ResponseTimeHandlerContext and writing the channel context — none of which anything consumed. Reactor Netty now owns the default ObservationRegistry so it can tell whether any observation handler, predicate, filter or convention has been registered: the ObservationConfig accessors are package-private and the documented tracing setup mutates the default registry in place, so registry identity alone is not sufficient. When the registry is the untouched default, the recorder records the response-time timer directly — same meter, name, tags and value — and skips the Observation lifecycle. Any customization re-engages the full lifecycle, so tracing is unaffected. Signed-off-by: samlightfoot <samueldlightfoot@gmail.com>
samueldlightfoot
force-pushed
the
client-metrics-recording-perf
branch
from
August 6, 2026 15:54
cb0b4e3 to
1b249bf
Compare
Member
|
I'm ok with that, but I don't feel like introducing it to the |
Contributor
Author
SGTM - no rush! |
samueldlightfoot
marked this pull request as ready for review
August 9, 2026 09:47
Match TrackedObservationConfig's overrides against ObservationConfig's mutators by full signature rather than name, so an added overload of an existing mutator fails the guard instead of silently bypassing detection, and assert the discovered set is non-empty so a covariant return type upstream cannot make the check vacuous. Also use the precomputed responseTimeName in both recordResponseTime overloads, which the original change missed. Signed-off-by: samlightfoot <samueldlightfoot@gmail.com>
samueldlightfoot
force-pushed
the
client-metrics-recording-perf
branch
from
August 9, 2026 10:13
cb888b1 to
3f48655
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Change
With
.metrics(true)and no tracing configured, the client runs a full MicrometerObservationper request torecord one timer. Nothing consumes it. It is 43.4% of the allocation that enabling metrics adds to the client
event loop.
When the
ObservationRegistryis the untouched built-in default,startWritenow skips theObservationandrecordReadrecords theresponse.timeTimerdirectly. Same meter, name, tags and value.Deciding "untouched" needs Reactor Netty to own the registry:
ObservationConfig's accessors arepackage-private, and the documented tracing setup mutates the default registry in place rather than replacing
it, so registry identity alone can't answer it.
DEFAULT_OBSERVATION_REGISTRYtracks whether any handler,predicate, filter or convention was registered after Reactor Netty installed its own. Registering any of them,
or assigning
OBSERVATION_REGISTRY, re-engages the full lifecycle.The response-time meter name is also precomputed on the recorder rather than rebuilt twice per request.
Behaviour
Two visible deltas, both intended:
Observationon the channel context, so codereading
OBSERVATION_KEYoff a client channel finds nothing. Registering any handler, predicate, filteror convention — or assigning
OBSERVATION_REGISTRY— restores it.REMOTE_ADDRESStag onresponse.timenow usesformatSocketAddress, like every other client meter,instead of
netPeerName + ":" + netPeerPort. For anInetSocketAddressthe two are identical. For otherremotes — a domain socket, say — the tag loses the trailing
:the old form left when the port was empty.That is a meter-identity change for those users. The
NET_PEER_NAMEandNET_PEER_PORThigh-cardinalitytags are unchanged.
Benchmarks
Rig: H2C loopback, 32 threads, JDK 17, 180 s after a 30 s warmup,
SimpleMeterRegistryon the globalcomposite, metrics on in both arms, back-to-back in one session. Allocation sampled at a fixed
--alloc 512kinterval.