-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
x/net/http2: add Framer.WriteDataN method #66655
Comments
CC @neild |
I think this would need slight tweaks. Namely, from the docs of
In this case, the new |
I think my first question here is whether the better approach is for gRPC to copy As you point out, the |
Either of these would be nice, but not mandatory IMO. We can own the logic to pass the appropriate slices and maintain the size constraints ourselves. (I'm not even sure if the framer is currently aware of the max frame size, so this might be required anyway.)
That's not an unreasonable option. On the other hand, if there are bugs or vulnerabilities discovered, it's nice when code is centralized to also centralize the fixes to those problems. Similarly, if a more performant methodology could be found and agreed upon, then those benefits can be shared by everyone using a standard(ish) library. |
By that argument, gRPC should be using the entire HTTP/2 implementation from x/net/http2, not just the framer. Perhaps that would have been a good idea, but that ship sailed long ago. The proposal here ( |
Brad tried that before I even joined the team. It's still in the code, and some users use it. I would love to live in that world, but alas, it's not this one. I'm not sure whether the net/http server supports all the things gRPC needs to support, like BDP estimation, configurable keepalive pings, max connection age, etc, but if it doesn't, I am guessing it would be even more painful to add those features than adding a simple, optional function to the framer.
We don't have the resources to embark on a full framer rewrite at this time. So our choices are to fork it and add this simple method ourselves, or to add it to x/net/http2. I'd really rather not fork the whole package for something so small. If you're saying that's the only path forward, we will consider it, but it feels wrong. This is a very trivial extension of the existing API and would not impose any new limitations of future work. |
Is there a path forward here? If I send a CL, would it be considered? |
An alternate possibility is that you add this one function to your own implementation:
~20 lines, fairly straightfoward. (I did omit checking that the data size is < 2^24, so a few more lines for that.) This requires that you have access to the framer's This will also be rather more efficient than adding a I might modify the function signature a bit, though, to avoid the need to build a
Another question is whether it's really all that useful to combine these writes into one frame; the per-frame overhead is 8 bytes, which isn't nothing, but splitting one chunk of data across two frames doesn't seem all that expensive. I'll assume you've measured this, but if you haven't it might be worth thinking about. |
This proposal has been added to the active column of the proposals project |
@neild what do you think the right outcome here is? |
I'd like to know whether the If we do make an API change, I'd prefer:
This should be more adaptable and should perform better, since it avoids an unnecessary copy of the data. |
The function proposed above ( I think the question that needs answering is: what is the purpose of this library?
The alternative proposed ( |
I don't have the historic context on how From my perspective:
Anyway, I'm really not very excited about adding new methods to |
I still think it would be good for future proposals if we had some kind of official answer to my question about the goals for the library. It seems like you're saying you'd prefer (1): "exported by accident; bug fixes only" but are willing to do (3): "extended within reason" as long as it's very minor. In the meantime, we will investigate stopping our use of it, but that would be a longer-term project. I can send a CL for |
I agree that gRPC should probably copy this code and adapt it to their needs, but it's also fine to add the method. |
@rsc: Is that a proposal committee decision? Or is this out-of-scope for proposal committee, being in x/?
"It's a basic, functional, minimal implementation."
|
Have all remaining concerns about this proposal been addressed? The proposal is to add:
|
If that's the case, then you can close this request if you don't want it. The basic functionality is provided already. We have an intern starting soon who will look into removing our dependency on this package. That's very unfortunate from the standpoint of open source software and the implications of security vulnerabilities, but if it's your intention to maintain only the bare minimum of functionality here, with no consideration for performance, then that's clearly our only option. |
This seems like an extreme statement to make. Clearly we do care about performance. The performance win of this specific API seems low though. Even so, it's likely to be accepted. |
Based on the discussion above, this proposal seems like a likely accept. The proposal is to add:
|
Sorry, in light of all the pushback in this issue, I'm trying to get a handle on my question about how this package is intended to be maintained.
The win admittedly hasn't been measured. I'd be happy to do that experiment if it's helpful for justifying the change. For RPC payloads under 16kb, we are currently copying every byte into a separate buffer solely to add the 5 byte gRPC header and then call this method. We can't otherwise do any better right now given the APIs we need to work with (mainly: protobuf and the framer). |
No change in consensus, so accepted. 🎉 The proposal is to add:
|
Proposal Details
To write a data frame, the
x/net/http2.Framer
requires the data contents to first be accumulated into a single contiguous buffer. However, this is not always possible without requiring a copy. See this real-life example where a copy is required in order to construct the frame's contents before writing it. If we had an API like the following, this copy could be avoided:The implementation could be as simple as changing the append here into an append that loops over the slice of buffers instead of just the one buffer.
The gRPC code could then be changed to remove the copy and pass the 5-byte header buffer and the data buffer directly to the new method.
I'd also love to discuss other changes that could make the HTTP/2 Framer even more zero-copy friendly by transferring buffer ownership instead of using
io.Reader
/io.Writer
, but the proposal above would be a simple step that provides real incremental performance.cc @PapaCharlie, @atollena
The text was updated successfully, but these errors were encountered: