Skip to content
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

Minimalistic HTTP2 flow control API #53372

Closed
antonfirsov opened this issue May 27, 2021 · 9 comments · Fixed by #54755
Closed

Minimalistic HTTP2 flow control API #53372

antonfirsov opened this issue May 27, 2021 · 9 comments · Fixed by #54755
Assignees
Labels
api-approved API was approved in API review, it can be implemented area-System.Net.Http
Milestone

Comments

@antonfirsov
Copy link
Member

antonfirsov commented May 27, 2021

This is a replacement (next iteration) of #49897

Background and Motivation

Our current HTTP/2 receive window size is 64 Kb, which is too small for many scenarios. It leads to poor throughput, see #43086

We are working on a dynamic window extension algorithm, which is expected to automatically grow the receive window, resulting in good throughput for the vast majority of the users. However, there could be cases when providing manual control over the window size might be a better option. My recommendation is to expose an API proactively for those corner cases.

Examples

The algorithm needs RTT estimation which will be determined by sending PING frames periodically while reading the servers data. Although we are doing our best to make sure that we won't trigger today's server's PING flood detection with their default settings, theoretically it's possible that a strictly configured server may abort the connection. Facing such a case, a user could just disable the dynamic window algorithm (and therefore the PING frames), and set the window size manually.

Another use case: since HTTP2 flow control is hop-by-hop, poorly configured intermediaries may alter the window sizes with H2C in a suboptimal way. I've experienced this by tunneling the connection through a VPN, where some intermediary (firewall?) was intercepting and replacing the WINDOW_UPDATE frames. With that connection, it wasn't possible to reach the desired throughput by extending the receive window with WINDOW_UPDATE's, however setting a large initial window worked.

What about other knobs?

I'm thinking of other parameters like the threshold divisor, or our arbitrarily high connection window increment as implementation details.

Proposed API

public class SocketsHttpHandler
{
    public bool EnableDynamicHttp2StreamWindowSizing { get; set; } // = true;
    public int InitialHttp2StreamWindowSize { get; set; } // = 65535;
}

Usage Examples

var h = new SocketsHttpHandler {
  // Disable the dynamic window algorithm and the periodic PING frames
  EnableDynamicHttp2StreamWindowExtension = false,
  // Set a 16MB receive window manually
  InitialHttp2StreamWindowSize = 16*1024*1024
};

Alternative Designs

[Edited]

  • We considered exposing an AppContext switch / environment variable instad of EnableDynamicHttp2StreamWindowSizing . The disadvantages are: (1) less visible docs (2) less accessible - which means that the user has to do much more facing an issue. Also: (3) can not be fine-tuned per- SocketsHttpHandler. An explicit API feels better for this.
  • We discussed if we should share the API between HTTP2 and a potential HTTP3 flow control fine-tuning mechanism, but decided to keep them separate, see Minimalistic HTTP2 flow control API #53372 (comment)

Risks

None.

@antonfirsov antonfirsov added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label May 27, 2021
@dotnet-issue-labeler dotnet-issue-labeler bot added area-System.Net.Http untriaged New issue has not been triaged by the area owner labels May 27, 2021
@ghost
Copy link

ghost commented May 27, 2021

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

This is a replacement (next iteration) for #49897

Background and Motivation

Our current HTTP/2 receive window size is 64 Kb, which is too small for many scenarios. It leads to poor throughput, see #43086

We are working on a dynamic window extension algorithm, which is expected to automatically grow the receive window, resulting in good throughput for the vast majority of the users. However, there could be cases when providing manual control over the window size might be a better option. My recommendation is to expose an API proactively for those corner cases.

Examples

The algorithm needs RTT estimation which will be determined by sending PING frames periodically while reading the servers data. Although we are doing our best to make sure that we won't trigger today's server's PING flood detection with their default settings, theoretically it's possible that a strictly configured server may abort the connection. Facing such a case, a user could just disable the dynamic window algorithm (and therefore the PING frames), and set the window size manually.

Another use case: since HTTP2 flow control is hop-by-hop, poorly configured intermediaries may alter the window sizes with H2C in a suboptimal way. I've experienced this by tunneling the connection through a VPN, where some intermediary (firewall?) was intercepting and replacing the WINDOW_UPDATE frames. With that connection, it wasn't possible to reach the desired throughput by extending the receive window with WINDOW_UPDATE's, however setting a large initial window worked.

What about other knobs?

I'm thinking of other parameters like the threshold divisor, or our arbitrarily high connection window increment as implementation details.

Proposed API

public class SocketsHttpHandler
{
    public bool EnableAutomaticHttp2StreamWindowExtension { get; set; } = true;
    public int InitialHttp2StreamWindowSize { get; set; }
}

Usage Examples

var h = new SocketsHttpHandler {
  // Disable the dynamic window algorithm and the periodic PING frames
  EnableDynamicHttp2StreamWindowExtension = false,
  // Set a 16MB receive window manually
  InitialHttp2StreamWindowSize = 16*1024*1024
};

Alternative Designs

I'm not familiar with msquic flow control options, if there is an option to set the initial frame window size, we may consider to share the API between HTTP2 and HTTP3. @scalablecory thoughts? Is it worth an investigation?

Risks

None.

Author: antonfirsov
Assignees: -
Labels:

api-suggestion, area-System.Net.Http, untriaged

Milestone: -

@antonfirsov
Copy link
Member Author

antonfirsov commented May 27, 2021

@geoffkizer @scalablecory @CarnaViire let me know if you have any concerns or thoughts, we should catch the 6.0 train with this.

@scalablecory
Copy link
Contributor

Seems good to me. Maybe change Extension to Management or something in case we want to add window size reduction at some point.

@geoffkizer
Copy link
Contributor

geoffkizer commented May 31, 2021

Yeah, and "Extension" is kind of a weird word, it makes me think you are extending the code somehow.

I would suggest "EnableDynamicHttp2StreamWindowManagement" or "EnableDynamicHttp2StreamWindowSizing".

@geoffkizer
Copy link
Contributor

geoffkizer commented May 31, 2021

@scalablecory Do you think these apply to HTTP3 as well? I can't recall how window management works with msquic.

edit: msquic handles all of this for us, right? So we don't need a property here.

@antonfirsov
Copy link
Member Author

EnableDynamicHttp2StreamWindowSizing sounds the best to me, changed the proposal.

@antonfirsov antonfirsov added api-ready-for-review API is ready for review, it is NOT ready for implementation and removed api-suggestion Early API idea and discussion, it is NOT ready for implementation labels Jun 1, 2021
@antonfirsov
Copy link
Member Author

antonfirsov commented Jun 1, 2021

Regarding QUIC & HTTP/3: I've been thinking about this, and now my opinion is that even if we decide to expose QUIC flow control options, it's better be done in separate properties in the future.

I flipped this to be ready for review, @scalablecory @geoffkizer let me know if you disagree and we should discuss/change something before moving on.

@antonfirsov antonfirsov removed the untriaged New issue has not been triaged by the area owner label Jun 1, 2021
@antonfirsov antonfirsov added this to the 6.0.0 milestone Jun 1, 2021
@scalablecory
Copy link
Contributor

I think it's fine to make this HTTP/2 specific, because in HTTP/3's case the flow control is handled automatically by the transport (just like TCP).

I could see us adding ways to tweak QUIC in the future, but we'd probably encourage setting those via a QuicConnectCallback similar to how we encourage setting TCP options via ConnectCallback.

@scalablecory scalablecory added the blocking Marks issues that we want to fast track in order to unblock other important work label Jun 10, 2021
@terrajobst
Copy link
Member

terrajobst commented Jun 14, 2021

Video

  • We believe EnableDynamicHttp2StreamWindowSizing could be served as an app context switch, because it's just an escape hatch
    • The name should follow app context switch naming conventions but use "Disable" rather than "Enable" naming, because it's about turning it off.
namespace System.Net.Http
{
    public partial class SocketsHttpHandler
    {
        public int InitialHttp2StreamWindowSize { get; set; } // = 65535;
    }
}

@terrajobst terrajobst added api-approved API was approved in API review, it can be implemented and removed api-ready-for-review API is ready for review, it is NOT ready for implementation blocking Marks issues that we want to fast track in order to unblock other important work labels Jun 14, 2021
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Jun 25, 2021
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Jul 8, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Aug 7, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-approved API was approved in API review, it can be implemented area-System.Net.Http
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants