-
Notifications
You must be signed in to change notification settings - Fork 843
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
Memory Mode: Adding support for OTLP HTTP Exporter - First draft #6171
Memory Mode: Adding support for OTLP HTTP Exporter - First draft #6171
Conversation
@jack-berg Here it is |
@jack-berg Can you have a look at this draft to see if the idea is ok? |
There's a lot to review here. I think we can break this apart to separate the establishment of the key patterns from the repetition of applying that pattern to all the different types in the MetricData hiearchy. I think the place to do that is to stop going down the rabbit whole after MetricMarshaler. Up in I'm going to hold off on looking to closely its more manageable, but some high level comments:
@laurit I know you had done some experimentation with this type of thing. I wonder if you have taken a look and have any thoughts? |
The idea in this PR is to review it top to bottom in IntelliJ just to get the hang of the pattern and see if it makes sense so I can know if I can proceed to do it for all. I can do the work of downsizing it, but it's a lot of work :) If it's absolutely hard and too difficult to view in IntelliJ, I will do it.
I didn't add it yet since I wanted confirmation on the pattern and proposal of immutable/mutable concept first. My plan was to add it, which will be one in a recursive manner.
I have thought about it and implemented part of the solution in this PR. |
Last year I experimented a bit reducing allocations for OTLP trace exporter. I took a slightly different approach. Instead of pooling the marshaler objects I removed them all together. Marshaling is essentially a 2 step process: firstly compute the size of the data and then serialize it. The need to know the size of each element (and elements can have child elements) before the element can be written to output stream makes it a bit tricky to do the marshaling without extra allocations. With the current immutable marshalers size is computed in the constructor and serialization is done in |
@laurit Your design was the first on my list of possibilities to solve this. I was hesistant to go with it since I was afraid it would be too complicated to maintain, but after drawing out some pseudo code, maybe it's not so bad, and it has a significant advantage in that memory cost is a lot less. If I summarize your approach: Basically, build a tree of objects that only contain the size., Then serialize using those pre-computed sizes. If I put it in pseudo-code, it looks something like this:
The "node" in the tree is Each type of message in the protobuf, which today has a *
The main idea is that For example, if we take the protobuf message
then in
I'm ok with going with this approach. |
@jack-berg WDYT? |
I think the approach is promising. Can we see what it looks like for a small portion of the encoding, like resource? Refactoring resource to use this approach should allow us to evaluate the patterns without all the work associated with refactoring the whole metric hierarchy. |
@jack-berg @laurit Finally found the time and finished the prototype code for the above design. The PR is at: #6273 I've started at the |
This PR has been superseded. See 1.38.0 release notes for details. |
This PR aims to showcase the idea of using pooled mutable Marshaler objects instead of immutable ones to add support to Memory Mode.
I created two classes for each
Marshaler
: a mutable and an immutable version. Both inherit from a base class containing the shared logic of serializing and computing the size.This was a definitive rabbit hole. I started with
MetricsRequestMarshaller
and ended up much deeper than I wanted :)So I simply stopped at some point, marking with TODOs where to continue, and left many code sections uncompiled.
The main goal is to see if this pattern makes sense.
Notable things:
String
since it already exists in the originalMetricData
input so that we can avoid memory allocation. I needed to convert the String to aUTF-8
byte array without memory allocation. I copied theUtf8
class from the protobuf library and trimmed it, only to have a conversion method from String to ByteBuffer containing the utf8 bytes. I reuse that ByteBuffer using thread-local. You don't need more than one.DynamicList
in the mutable version, which is like theDynamicPrimitiveLongList.
The idea is that whenever I need more room, I add a small ten-item array instead of duplicating it, which can sometimes be wasteful in space.In short, the code is a rough draft, and attention must still be paid to the scope of methods and many other things - but in the future.