-
Notifications
You must be signed in to change notification settings - Fork 961
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
Add metrics support for Netty 4.x #3742
Conversation
In case you are interested, it is possible to add these additional metrics out of Netty event loops : netty/netty#9080 Sadly I have never completed it, but it should be simple And the same, here: netty/netty#11293 (comment) |
This PR is focusing on Netty 4.x - Netty 5.x is still in alpha version, we can add that support anytime. MeterBinder setupThe Reactor team is using a I initially adopted that approach but rolled it back for two reasons:
Maybe this cache could be handled still as a Reactor Netty opinion and still leverage the binders provided here? Metrics names configurationIn my initial proposal I said that I would try to provide a way to customize metric names. Because of the number and structure of metrics, this PR doesn't allow that. Instead, I think that libraries and apps could use a Metrics
This PR does not instrument the DNS infrastructure and I didn't dig much in that area. I'm not sure we can use a Prometheus format sampleHere is a sample of Prometheus format I captured while testing the instrumentation on a running Netty server.
|
As someone who isn't a Netty expert, I think so. I'd love to hear from others who know more about Netty usage than me, though. In the past, the strong need to customize the metric name at the binder level came from there being multiple instances of the instrumented thing with potentially different tags on it, like ExecutorServiceMetrics. Will there be multiple instances of the binder in an app with a need to distinguish between the metrics from each? Netty being shaded was something I thought about, but if the package is different, these binders won't be usable anyway.
I think it's fine to leave that as out-of-scope for this PR. If any users would like us to add this, please open an issue requesting it (or a pull request). |
if (eventExecutor instanceof SingleThreadEventExecutor) { | ||
SingleThreadEventExecutor singleThreadEventExecutor = (SingleThreadEventExecutor) eventExecutor; | ||
names.add(singleThreadEventExecutor.threadProperties().name()); | ||
new NettyEventExecutorMetrics(eventExecutor).bindTo(this.registry); |
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.
Without being a Netty expert, having users loop like this to bind each feels a bit weird to me. Would there be a reason a user would want metrics for some event executors in an EventExecutorGroup but not others? I wonder if we should use a higher level abstraction in NettyEventExecutorMetrics and add metrics for each executor for users rather than make them bind each one individually.
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.
I don't get this question.
Basically you have EventLoopGroup
with EventLoop
s. Every EventLoop
has a name and a queue with pending tasks. What you are proposing is to have metrics on the EventLoopGroup
is that correct? Typically the EventLoop
s are not equally loaded.
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.
I'm saying we should have metrics on all of the EventLoops like this test does, but without making users do new NettyEventExecutorMetrics(eventExecutor).bindTo(this.registry)
for each individual EventExecutor
. Instead we could take the EventLoopGroup
as a parameter and register metrics for each EventExecutor
so users only need to call, e.g. new NettyEventExecutorMetrics(eventLoopGroup).bindTo(this.registry)
once rather than iterating over each element like now. Basically the question is does it make sense to make things as granular as they are now? It only makes sense to me if there is a case you would only want metrics for some EventLoops in a group but not all of them. If you always want all of them, we should just take the group as a parameter and iterate internally so users don't have to. Does that make more sense?
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.
I agree with you, it is just easier in Reactor Netty at this point to do it per EventLoop
. Definitely you want metrics for all EventLoop
s in the EventLoopGroup
.
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.
I guess I could add a constructor variant that takes the entire EventLoopGroup
?
This implementation was targeting the "lazy" case where the current EventLoop
is found in the given channel during its initialization. Something like:
@Override
public void initChannel(SocketChannel channel) throws Exception {
ByteBufAllocator alloc = channel.alloc();
if (alloc instanceof ByteBufAllocatorMetricProvider) {
// this concurrent check must be implemented by micrometer users
if (isAllocatorInstrumented(alloc)) {
new AllocatorMetrics(((ByteBufAllocatorMetricProvider)alloc)).bindTo(prometheusRegistry);
}
}
// this concurrent check must be implemented by micrometer users
if (isEventLoopInstrumented(channel.eventLoop())) {
new EventExecutorMetrics(channel.eventLoop()).bindTo(prometheusRegistry);
}
channel.pipeline().addLast(new HttpRequestDecoder());
channel.pipeline().addLast(new HttpResponseEncoder());
channel.pipeline().addLast(new CustomHttpServerHandler());
}
Yep that's something that Reactor Netty has also in its backlog reactor/reactor-netty#1433 |
Reactor Netty will need to change the name if we want to keep backwards compatibility ... |
@franz1981 @violetagg I think this type of instrumentation really belongs in Netty directly. I'd be happy to expand metrics here once this API is available in Netty. We do maintain more involved instrumentations, but they usually rely on official extension points that are not likely to change. |
I've just pushed additional changes in a separate commit that:
I will squash this commit before merging this PR, once we're done with the review cycle. |
For this one netty/netty#9080 I think it's fine; but please consider that in Netty we don't modify public APIs unless marking them as For this one, is different, because is something that Netty cannot provide nor decide by it's own, if the dynamic that allow it work is clear: if not, I can better explain it here instead. |
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.
Looks good to me. I would like to get rid of id
on the allocator metrics if possible because it doesn't seem particularly meaningful to a user looking at the metrics. Due to my lack of experience with Netty, I don't know if there would ever be multiple instances of the same type of allocator in the same app to instrument. If not, it seems like we could get rid of id
. However, it does seem theoretically possible for their to be multiple allocator instances of the same type.
* @since 1.11.0 | ||
* @see NettyMeters | ||
*/ | ||
public class NettyAllocatorMetrics implements MeterBinder { |
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.
Could we add a typical usage example to a JavaDoc? I don't know if it will be common knowledge for Netty users from the API defined here how/where to get the type to pass to the constructor.
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.
Tests do show this to some extent, but far from real usage, so +1 on @shakuzen 's suggestion.
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.
@alesj we've added code snippets in the reference documentation. Does this work for you?
This commit adds two new `MeterBinder` implementations for instrumenting Netty 4.x: `NettyAllocatorMetrics` and `NettyEventExecutorMetrics`. `NettyAllocatorMetrics` will instrument any `ByteBufAllocatorMetricProvider` and gather information about heap/direct memory allocated; additional metrics are provided for pooled allocators. `NettyEventExecutorMetrics` will instrument `Iterable<EventExecutor>` (typically, `EventLoop` or `EventLoopGroup` instances) and count the number of pending tasks for all. Metrics and tags are described in the `NettyMeters` class. Closes micrometer-metricsgh-522
This commit adds two new
MeterBinder
implementations for instrumentingNetty 4.x:
NettyAllocatorMetrics
andNettyEventExecutorMetrics
.NettyAllocatorMetrics
will instrument anyByteBufAllocatorMetricProvider
and gather information about heap/direct memory allocated; additional
metrics are provided for pooled allocators.
NettyEventExecutorMetrics
will instrumentEventExecutor
(typically,EventLoop
instances) and count the number of pending tasks for each.Metrics and tags are described in the
NettyMeters
class.Closes gh-522