-
Notifications
You must be signed in to change notification settings - Fork 1k
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 Meter.Cache for dynamic meter registration #4092
base: main
Are you sure you want to change the base?
Conversation
@qweek Please sign the Contributor License Agreement! Click here to manually synchronize the status of this Pull Request. See the FAQ for frequently asked questions. |
@qweek Thank you for signing the Contributor License Agreement! |
Thank you for the PR! We are planning to do something similar (please see below), it seems this PR shows a different way to implement that.
Just to clarify things: Micrometer is capable of doing this, the
I'm not sure the PR does this or it works as intended. Builders are not meant to be shared (they are mutable) and as far as I can tell (maybe I misunderstood something), every time you ask for a new (tag) value, the builder will be modified ( I think this is somewhat similar to this approach that we are planning to implement in 1.12 (in the next 2 weeks 🤞🏼): #535 (comment)
vs.
I'm not sure the cache is needed or it's a real benefit in general. Also, items are never removed from the cache, e.g.: meters can be removed from the registry so this is a memory leak by definition. Sometimes meters have to be removed and re-registered, see the Kafka instrumentation. 🙁 |
Yep, as you mentioned, I'm aware of this and
No, I intentionally use immutable operations.
In second case, as side effect you will always override internal builder tags.
Yes, it similar approach, but it will have same problems as described before: unnecessary work for process Tags and build Meter. According to memory leaks, I agree that it's possible, but can be described in documentation. It doesn't affect existing code and we still have possibility to create meters with usual approach. In some cases we already have methods which create meters, but didn't have way to close it without specific logic.
Unfortunately no, it was one of the main reasons why we implement this change, because existing approaches highly affect Young GC, lead to minor pauses and also use a lot of CPU. |
I think that is necessary in some use cases. You might not use
Indeed; sorry, somehow I misread/interpret it. That extra private
With your idea using the extra
I don't think this would be fortunate, users are using Micrometer in various ways and I don't think providing them a seemingly harmless method that just creates meters but can leave garbage behind is a good idea.
This is by design but you can still get a reference to this
From the young-gen perspective, I think you are right, but I was talking about the overall impact: "if having a lot of short-lived builder instances is better or not from the memory perspective". The trade-off is basically more garbage in young-gen (your pain point) vs. increased heap usage on the long run. Could you please check the changes I made on the proposed solution for #535 that now does not need a builder thanks to your idea jonatan-ivanov@228b2b0 and tell me how much would it help in your use-case? I think I would still prefer being able to pass all the extra tags instead of just one value: timerProvider.get("first.value").record(latency);
//vs.
timerProvider.apply(Tags.of("name", name)).record(latency); I think that approach is more explicit (readable), looking at only |
Closes micrometer-metricsgh-535 See micrometer-metricsgh-4092 Co-authored-by: qweek <alnovoselov@mail.ru>
I didn't mean that filters itself are unnecessary (we actually use them), but when you convert MeterId -> MappedMeterId it is usually expected that after applying all the filters you will get the same Id.
I happy that you like idea with On the contrary, it seems to me that the idea of copying a builder can be very useful when implementing a factory :)
As you said, Gauge is different case, to make it work same way as other meters we need:
Tell me what you think about this, if you are interested in such an implementation, I can make a proof of concept. |
I'm not sure I follow/understand, you need to look up the Meters anyway, right? Should we create a new issue for this?
We usually don't do that but I can see some advantages of it, I added a comment to the PR: #4097 (review)
Yeah, that's what I did originally (copy ctor) but with your idea, the extra Builder object can be eliminated. Also, I'm not sure it is needed to create meters with different builder settings (other than tags), what would be the use case for that? I think the other settings of the builder do not create a new meter when you change them so do not seem that useful to me.
I feel doing something like this to |
Closes micrometer-metricsgh-535 See micrometer-metricsgh-4092 Co-authored-by: qweek <alnovoselov@mail.ru>
@jonatan-ivanov We have also faced the issue of using the default builder pattern to record values in a Meter. There are 2 big concerns we had,
See this repo where I have a few benchmarks run where there was a clear issue with the current approach to record values. In the above example, I have commented out the meter filter to just show that there is still a clear difference if there are no meter filters involved. But in real uses, we will have multiple meter filters and that will only be slower (also increase allocation). And when these meter filters involve adding tags/manipulating tags/changing the name of the meter it just gets worse. We were forced to use a Cache for directly interacting with the meters to have better performance. This is also not straightforward, as we need to handle meter removal and invalidating the cache when meters are removed and other cases. Yet we encourage our internal users to use the cache to have an improved performance number. |
This comment was marked as outdated.
This comment was marked as outdated.
@lenin-jaganathan Could you please check if the new |
I explored the option provided in the new version to attach tags dynamically. But, my ask still differs a bit from what is being discussed here. My concern is calling the register on the registry seems to be a costly operation (especially with meter filters this creates a lot of Garbage and exec time is also elevated highly). What I was looking for is a cache-like solution that will return the existing meters for a given set of meter names, tags, etc. |
I think #2275 relates more to the issue I discussed and I will add it here. |
If you would like us to look at this PR, please provide the requested information. If the information is not provided within the next 7 days this PR will be closed. |
Summary
This PR aims to add Meter.Cache for dynamic meter registration. This allows to create meters with dynamic tags, making it more customizable and adaptable to systems with tags depending on external sources. This change is backward-compatible.
Changes
Introduce additional register() method in specific Meter to create Meter.Provider for ad-hoc Meter creation.
Why is this important?
Currently, Micrometer's Meter doesn't provide a straightforward way to customize tags without additional allocations in runtime. This PR eliminates the need to build, deduplicate and sort Tags on each call and allow to re-use metrics builder, thereby simplifying metric management.
Backwards Compatibility
This feature is backward-compatible because it doesn't affect existing register() method.
Test Coverage
MeterCacheTest class has been created to include tests that verify this new functionality, ensuring that all basic metrics supports dynamic registration.
Usage Example
After this change, you can use new register() method to create metric with dynamic tags.