micrometer
micrometer copied to clipboard
Improve the performance of meter interaction
Please describe the feature request. To interact with a meter (recording values), the preferred pattern documented is to use the Builder to create a meter and interact with it. For example, the following code would create a counter,
Counter counter = Counter
.builder("counter")
.baseUnit("beans") // optional
.description("a description of what this counter does") // optional
.tags("region", "test") // optional
.register(registry);
Once the counter is created we would call the counter.increment()
to increment the counter. For a simple counter like this, we can save it in a variable and call the increment method whenever we want to increment. Now, if we want to add a tag whose value will be available only during runtime, we cannot store it in a simple variable. There are two ways to do it,
- Directly call the increment method on the object returned by the builder. Since, the registry will make sure that only one meter will be registered for a
name
andtag
set we would get the same object all the time and can call increment on it. Again, so simple it seems but in a real-world scenario, applications would be having meterfilters registered which will have to be run every single time we invoke the builder. Since,Meter.Id
is immutable we keep on creating new meters if we want to add tags/modify tags/modify the name, etc. But all the code runs and would eventually return an already created meter in the registry. This becomes a huge overhead in the real-world use case where we interact with meters thousands of times per second and generate a very high amount of garbage data. - To work around the problem in
1
, we tried a few different things and eventually used aHashMap
to store the different tags as the key and the returned meter as value. So, the next time you need the meter for a tag and name combination we would avoid all the intermediate steps and directly return the actual meter. This surely had a huge performance gain for us which is available in the above-mentioned repo. It opened up a few issues like, i. What if a meter is removed from the registry? Then our cache will be holding reference to a meter that is no longer reported and would be incrementing that. We then listened to the onMeterRemoved and removed the meters from the cache. ii. What if someone added a meterfilter? That would basically invalidate all the meters. Micrometer doesn't enforce strict rules about when a filter can be added. But we sort approached meter registry state as a immutable thing and didn't want to invalidate the entire cache because that micrometer doesn't invalidate meters when meter filters are registered.
To address the above mentioned problem and to improve the overall performance of micrometer meters, a built-in way to map the preMapped Id's to mappedId's with O(1) retrieval time with minimal garbage generation could be introduced.
Reference:
- MicroBenchmarking with different cache options - https://github.com/lenin-jaganathan/micrometer-benchmark/
Rationale To make micrometer meter interaction faster and lightweight.
Additional Context Some extent of this is also discussed in https://github.com/micrometer-metrics/micrometer/issues/3461