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

http.sys; add opt-in support for kernel-mode response buffering #47776

Merged
merged 3 commits into from Jun 15, 2023

Conversation

mgravell
Copy link
Member

@mgravell mgravell commented Apr 19, 2023

http.sys; add opt-in support for kernel-mode response buffering

Adds support in for buffered responses when using http.sys, to avoid performance problems in small-write/high-latency scenarios.

Description

As per linked issue, when using http.sys, in some scenarios, high volumes of small writes with high latency may cause significant performance impact, due to lack of a Pipe buffer in the http.sys implementation; as a simple workaround, here we optionally enable the http.sys support for response buffering as a global flag.

This is exposed by a new HttpSysOptions.EnableKernelResponseBuffering option.

This work is based on the very old (and not mergeable) work in #418, with some additional input - credit to @davidni

It is also planned to back-port this feature to net6/net7 (with the property internal - no change to public API), via an app-context switch "Microsoft.AspNetCore.Server.HttpSys.EnableKernelResponseBuffering"; this switch detection is retained in the default value to avoid issues for consumers when upgrading.

We have briefly discussed some new feature to allow per-request enable/disable, but have not implemented that at the current time. We can revisit that in the future.

Also considered: implementing a full Pipe implementation in the http.sys code with the pipe consumer writing to http.sys; attempting to minimise code impact until we have a definite demand for that.

Fixes #14455

Fixes #5852

Impact is hard to benchmark in a local network - latency is key; however, the change has been successfully validated internally via a private build. Ask me for details if you're curious. As a summary of the validation scenario - a large payload streaming operation that reads (proxies) an external request and mirrors that to response writes:

  • without this change: takes over 3 minutes and eventually fails (not having transferred all the information)
  • with this change: completes successfully in 8-10 seconds

@mgravell mgravell added feature-httpsys api-ready-for-review API is ready for formal API review - https://github.com/dotnet/apireviews labels Apr 19, 2023
@ghost
Copy link

ghost commented Apr 19, 2023

Thank you for your API proposal. I'm removing the api-ready-for-review label. API Proposals should be submitted for review through Issues based on this template.

@ghost ghost removed the api-ready-for-review API is ready for formal API review - https://github.com/dotnet/apireviews label Apr 19, 2023
@mgravell mgravell added api-ready-for-review API is ready for formal API review - https://github.com/dotnet/apireviews area-perf Performance infrastructure issues labels Apr 19, 2023
@ghost
Copy link

ghost commented Apr 19, 2023

Thank you for your API proposal. I'm removing the api-ready-for-review label. API Proposals should be submitted for review through Issues based on this template.

@ghost ghost removed the api-ready-for-review API is ready for formal API review - https://github.com/dotnet/apireviews label Apr 19, 2023
@mgravell
Copy link
Member Author

OK bot; have it your way; API change submitted separately

@davidni
Copy link

davidni commented Apr 19, 2023

Happy to see this finally making it to supported releases, thanks @mgravell!

@mgravell
Copy link
Member Author

mgravell commented Apr 19, 2023

@davidni thanks for your original work - the above is almost exactly that (it was completely impossible to merge the original PR, sorry - but I did try to at least acknowledge credit!) - for your interest, only minor tweak was to ensure that all writes use the flag (to avoid http.sys getting confused), and the app-context switch (which you can probably infer means "someone needed the feature, and can't use net8 yet; we can't change the pre-net8-API without a very good reason"); the main problem I had here was validating it!

Copy link
Member

@Tratcher Tratcher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you at least summarize the perf improvements observed?

src/Servers/HttpSys/src/HttpSysOptions.cs Outdated Show resolved Hide resolved
src/Servers/HttpSys/src/HttpSysOptions.cs Outdated Show resolved Hide resolved
@BrennanConroy
Copy link
Member

Can you at least summarize the perf improvements observed?

And has this impacted other scenarios besides the high latency + small writes + large payload scenario?

@mgravell
Copy link
Member Author

Can you at least summarize the perf improvements observed?

added in main post

@BrennanConroy
Copy link
Member

From the docs https://learn.microsoft.com/windows/win32/api/http/nf-http-httpsendresponseentitybody

Applications using asynchronous I/O which may have more than one send outstanding at a time should not use this flag.

Does this mean the entire application can't have concurrent sends? Are we preventing overlap when this is set? Am I misunderstanding the docs?

@amcasey
Copy link
Member

amcasey commented Apr 25, 2023

@mgravell What's left here?

@JamesNK
Copy link
Member

JamesNK commented Apr 26, 2023

Blocked on API review: #47777

@JamesNK JamesNK added the blocked The work on this issue is blocked due to some dependency label Apr 26, 2023
@mgravell
Copy link
Member Author

@BrennanConroy we already block (synchronously or asynchronously as appropriate) individual writes - concurrent parallel writes and overlapped (i.e. not awaiting a WriteAsync) is always going to be unsupported, regardless of API or server implementation. Which is a long way of saying "no change here".

@davidni
Copy link

davidni commented Apr 26, 2023

Side-note for posterity -- when I played with HTTP.sys perf on Asp .NET Core back in the day, one of our experiments was to NOT enable HTTP.sys buffering, and instead to do overlapped writes, ensuring there were always at least N outstanding writes. This helped improve perf in our scenarios (proxying large responses from a destination service -- before YARP), but (surprisingly at the time) we were never able to achieve the same throughput that http.sys kernel buffering afforded.

@ghost
Copy link

ghost commented May 4, 2023

Looks like this PR hasn't been active for some time and the codebase could have been changed in the meantime.
To make sure no breaking changes are introduced, please leave an /azp run comment here to rerun the CI pipeline and confirm success before merging the change.

@ghost ghost added the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label May 4, 2023
@halter73 halter73 linked an issue May 11, 2023 that may be closed by this pull request
@davidni
Copy link

davidni commented May 18, 2023

This is no longer blocked, is it? Per #47777, the proposed api change is reviewed and approved.

Sugg removing the blocked tag.

@mgravell mgravell removed the blocked The work on this issue is blocked due to some dependency label May 18, 2023
@amcasey amcasey added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Jun 2, 2023
@mgravell
Copy link
Member Author

(rebased as part of final validations; preparing to merge)

@mgravell mgravell enabled auto-merge (squash) June 15, 2023 18:04
@mgravell mgravell merged commit f8c1bb3 into main Jun 15, 2023
25 checks passed
@mgravell mgravell deleted the marc/kernel-buffer branch June 15, 2023 18:28
@ghost ghost added this to the 8.0-preview6 milestone Jun 15, 2023
@adityamandaleeka adityamandaleeka added the blog-candidate Consider mentioning this in the release blog post label Jun 28, 2023
@ghost
Copy link

ghost commented Jun 28, 2023

@mgravell, this change will be considered for inclusion in the blog post for the release it'll ship in. Nice work!

Please ensure that the original comment in this thread contains a clear explanation of what the change does, why it's important (what problem does it solve?), and, if relevant, include things like code samples and/or performance numbers.

This content may not be exactly what goes into the blog post, but it will help the team putting together the announcement.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions area-perf Performance infrastructure issues blog-candidate Consider mentioning this in the release blog post feature-httpsys pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun Perf
Projects
None yet
8 participants