-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
.NET Core Http Support #16650
Comments
We are using the event-driven curl_multi interface, with many requests multiplexed onto the same event-handling thread. We've not seen evidence yet that switching to the socket_action APIs would yield any significant benefits, and if it did, we could. We did previously switch from just using the easy interface to instead using the multi interface, and that afforded significant benefits as we expected it would.
It provides everything that's needed, it's available everywhere we need it, it's well-implemented and well-tuned, it's constantly being maintained and improved, it's best-of-breed, etc. Why should a ton of engineering effort be spent reimplementing something when it's already available? For example, once we had CurlHandler implemented, having it light-up to support HTTP/2 was an hour or two's work... that would not have been the case if we had to implement HTTP/2 support from scratch on top of sockets. Are you proposing that on Windows we not take advantage of WinHttp and instead re-implement everything on top of sockets in managed code? For what value? And how is that different? |
I actually wholeheartedly agree with @clrjunkie on this one. Though I would say, you can get the best of both worlds if there were 2 implementations, a managed version for maximum portability across platforms and a native implementation that light up if there were specific features that were more optimal. There are other reasons to have purely managed implementations of things though. Take the websockets example. The native implementation on windows called into an OS component that was only available on windows >= 8 for the client and server! To this day there isn't a websocket client that works on windows 7 available on the .NET stack (there other open source options though). Also, look at Windows Store/UWP applications, they have a completely different abstraction for websockets because it was made into a "platform component". People porting .NET to new platforms should only have to port a few native components tied to the platform:
The rest of the stack can sit on top of those native intrinsics. It's very unfortunate that libcurl has to be ported as well but it did save us time implementing an http client so I understand. |
I'm not arguing against having a managed version built on top of sockets in addition to having one built on top of the platform's support, so that it can support cases where there is no platform support. But until we have a true need to invest in such a thing, I'm not sure why we would. It is a huge amount of work, it'll likely have a very long stabilization tail, it'll likely be missing features that are trivial to bring up on top of something like libcurl, it'll likely have worse performance, etc.
Which platform are you concerned about supporting today where libcurl doesn't already exist for it or isn't trivially ported to it?
The other component @clrjunkie calls out is libuv, which corefx doesn't use at all, but ASP.NET does. @davidfowl, given your argument, when is Kestrel moving to be completely managed built on top of System.Net.Sockets? ;) |
@davidfowl, and, PAL(Platform Adaptation Layer), Unwinder, Stack Walking, ... |
Yep! I can understand and agree with that. Still I would have opted for writing the managed implementation first as it has less overall downsides. The one in .NET Framework is already managed, though service point manager is an abomination 😄 . I see the appeal in using something that already works plus looking at the time constraints we have it probably made sense.
ARM devices? Android/iOS/Windows Phone? That was just one example, another might be platforms that don't have the full capability of windows (like missing winhttp etc.)
It would have been that way if it was around when we did it. We actually refactored some of kestrel to sit on top of any networking stack (libuv is just a byte pump). Though the existing networking APIs are not optimal 😄 and libuv is actually more portable that System.Net. |
As is libcurl.
It's available on ARM. It's available on Android. It's available on iOS. You don't need it for Windows, that's what the Windows-optimized platform-based implementations are for, but nevertheless... it's available on Windows.
And lacks various features we'd need to build, e.g. HTTP/2 support. Plus, additional features we'd like to enable that are trivial to support on top of what libcurl already has but would again require a complete custom implementation if it were built manually, such as using Unix domain sockets as a proxy. And as you point out in the side-mention of service point manager, it wouldn't have just been "copy the code and it works"... there's a non-trivial porting effort there as well, nevermind that the stuff it builds on wasn't implemented yet on Unix. Again, I'm not arguing against eventually having an implementation of HttpClientHandler that sits on top of System.Net.Sockets (and System.Net.Security, System.Security.Cryptography.X509Certificates, etc.), but at the moment there's zero need for that, and until we encounter a platform that demands it, I don't see value in spending effort on it. |
How did you measure? Did you compare with HttpWebRequest?
Not only do I strongly agree, but I would add that the way Daniel Stenberg supports the project is something to envy! Nevertheless, in my opinion things are not as simple as you describe:
Obviously one with much better C skills than I have can easily challenge this, but that’s not the issue; It’s my understanding that one of the goals of opening .NET is to allow the implementation to be more accessible to .NET developers so we can have more control over the API and the risks. Do we now have to be also SUPER C PROGRAMMERS?? Because in my opinion Libcurl is written by SUPER C PROGRAMMERS.
Yes I am. Putting aside how this might reflect upon the CLR as a platform for implementing high performance network communication:
|
..and let's not forget: we are talking about "APPLICATION LAYER" protocols. |
Who needs this? What's the common scenario that it falls into? Does Java support it? |
You asserted that our current implementation, which is event-driven and uses curl_multi_perform, is deficient as compared to an implementation that instead used curl_multi_socket_action. When we originally switched from just the curl_easy APIs to using the curl_multi APIs, we prototyped with both curl_multi_perform and curl_multi_socket_action. The latter had non-trivially more complicated code, and showed no significant improvement in either throughput or scale based on the typical usage patterns employed by HttpClient (the primary benefit would come at hundreds or thousands of concurrent downloads, as we'd be able to use epoll/kqueue instead of the poll libcurl uses in curl_multi_perform... but it would also come with some additional per-operation costs). If you can demonstrate otherwise, would like to submit a PR for the switch, and can provide detailed performance data highlighting the impact, we would be very happy to review. Otherwise, we can always change this in the future if it proves to be problematic, paying the complexity costs then.
This is the way of the unix world. It's also no different than if we make a fix in C# code and you want that fix before it's available in a package.
Yes
I don't understand this. If an app wants to use its own private copy of libcurl.so, it can.
I don't understand what you're suggesting here. Are you saying that we should only use code in the implementation of .NET that every developer can easily understand? Code to the least-common denominator of ability? Anyway, it seems we simply fundamentally disagree. That's fine. We do not have the time nor resources nor inclination right now to go and implement a new HTTP stack that would simply get us to a state no better than we're in now. You're absolutely welcome to implement your own HttpClientHandler on top of the other System.Net.* libraries and put it out as a NuGet package for anyone to consume. Might even make sense to add one to corefxlab if you were so inclined and if you had the time and dedication to keep it moving forward. |
I completely agree with @stephentoub A few points I would add specifically on the HttpClient topic:
|
I don’t want to invest any time in this, because I don’t believe in the approach to begin with. The whole reason I experimented with libcurl C api is to see if this is something I can ramp quickly so I can self-support the implementation and not be back at square one having a wall in front of the communication layer implementation (HttpWebRequest) now just from a technical perspective. However; If you are willing to work TOGETHER on porting HttpWebRequest than that’s a completely different story.
Big difference. As a developer I have much more control on what get into the build then what get’s into the O/S (shared library)
And if the app dependents on a native library that depends on a private copy of libcurl.so and the app also uses HttpClient can you load the library twice?? Why should the FW be part of this party?
For BCL always prefer to the least-common denominator of domain expertise (C#/.NET) when possible. Here definitely possible. Furthermore, considering the “complexity” in implementing curl_multi_socket_action, my concern here is about a much higher bar in complexity.
Give me an editor debugging experience on *nix first!! this was supposed to be the TOP priority before anything. I refuse to debug epoll events issues with Console.WriteLine. You should know your .NET people. |
Solution: Refactor.
Until you hit the problem at the layer.. and then your stuck! (praying a for a fix) |
I stop participating in threads when they turn to insults. I'm done with this one. Thank you for the discussion. |
What insults?? the fact that we are working for the past 15 years with VS where editor debugging is an inherent part of the workflow and mind set you call this insult? |
Re: Is curl suitable for iOS/Android when http proxy is used |
I guess there was a misunderstanding between you two. I feel @clrjunkie meant You should know your people, but @stephentoub read it like You should know your .NET Probably better for the .net community that everyone check their words and remove anything typed not in a good mood, so that we still have a chance to send Java to the museum. |
@xied75 You understood me correctly. It didn't even cross my mind that such wording could be interpreted differently and I apologize for that. I didn't mean to say "You should know your .NET". Having said that, after 20y of working with MS Tech (15y with .NET) and also spending past time working at a Microsoft product group I'm too often baffled by how things in .NET Core are prioritized, to a point where it's challenging to stay calm. In my opinion: "Networking API's" (e.g Http(s), Sockets, Sql Reference Client*) and "Developer Tooling" should be among the top three priorities (I'll let others speculate on the third. I centrally have my opinion but I prefer to stay on topic) This is mainly because most other areas do not require nearly comparable testing efforts and can be fixed along the way by users themselves if mature tooling are made available cross-platform. Every time I see an issue mentioning SIMD some pointer abstraction or some memory micro optimization that will most probably only be appreciated in an artificial benchmark I do "ooofff", as all these grab developer attention that would otherwise help to improve on what I believe are the top priorities. if I was to write the .NET Core mission statement it would not be about performance improvements, "cloud-ready", "diet" or any other superlative. It would simply be summarized in one word - Accessibility Because:
Relying on 3rd-party Native Http Api's that are written in C make a core area in .NET Core inaccessible to managed developers . *Sql Reference Client - Since virtually all ADO.NET DB Drivers share 80% of the high level requirements (API Surface, Connection Pooling, retry logic, etc.) It would be wise to invest not only in coding a robust SQL Client for SQLServer but also document and record a code review session so other ADO.NET Driver developers can build upon the existing implementation and focus mainly on the protocol parsing logic. |
To each their own but I must say I disagree. In my mind the vast majority of developers who use .net will never dive into the actual .Net core code, much less such a low level apis as the libuv stuff. Most people will just want to get their app to market. Imo, .Net core is not a sample for people to use as reference when they attempt to learn how to write a network stack (or what have you), its a tool for writing apps. As such I think it should to all it can to make those apps run well/fast. If anything i'd like to see more native platform stuff, if that would increase performance. Besides, its not like everything in the .Net core is c# anyway, there is plenty of c/c++ and even asm to go around :) -edit- |
I agree. The majority of .net developers (as well as others) will probably understand.NET Core as a version of Microsoft .NET for linux/mac, no more no less. However, the majority of .NET developers do not participate in this project and do not make strategic decisions on framework of choice. Do you really think that companies like DropBox, Pintrest, Netflix care that LibCurl/LibUV saved Microsoft time? Do you really think they just buy into abstractions without looking under the hood to assess the risk? Have you seen how Google implemented their C# gRPC client? (hint: Pinvoke I/O Completion Port) Do you really think these companies aren't asking themselves how all this fit's together?
I agree. The only thing I suggested was to help other DB Client developers to leverage the investment made in SQL Client, because if Microsoft wants' to have MySql and PostgreSQL users run on Azure AND use other MS/.NET Technologies it would be is in their best interest that DB Drivers are in place. It's very important factor when choosing a FW. BTW, I think they mentioned that they are actually working on this with 3rd party in a past developer standup.
I should have made myself more clear. This issue is primarily about .NET Core HTTP components as they apply to server side scenarios and service-to-service communication. I agree this has much lower impact on the majority of client App developers.
Of course, all I/O is ultimately implemented in native languages, and I don't have anything against C/C++ or asm. I occasionally use 3rd party libraries written in C/C++ via PInvoke, but as I mentioned in one of my previous posts above, from my experience, it's one thing to debug and reason about syscalls that have very narrow semantics which rarely change and it's a completely different effort (and risk) to deal with application level protocol issues that are entirely implemented in Native languages.
Ohh, I disagree.., C Code is not the problem, it's how you deal with a complex C codebase that's over a decade old - that's the problem. Heck .NET Core itself is a solution to legacy problems in the "Full .NET Framework" just on a "Managed Level". |
I honestly doubt that level of technical audit is very common unless you're building a moon lander or a nuclear power plant, but even so, suppose that they are, wouldn't the goal of such an audit be to determine reliability and security first and foremost? All respect to the amazing skill of the .net teams, but writing a new managed network stack from scratch will not have the same battle cred as something that has existed and been used for years. Besides, when .net was closed, no one could check this kind of stuff anyway and high profile, non-Microsoft shops still used .net. Also, companies as the ones you mentions do care about time to market, and if Microsoft can deliver .Net core faster, that will translate to faster time to market for customers as well When I say "app" I do actually mean any kind of solution, server side or client. I firmly believe that most customers sees .net as a tool to solve their business problems, and trusts Microsoft to make the right calls about the internals. I think that if there is some specific concern about libuv from a performance, security or usability perspective that effects users of the framework, then that's a reason for looking at alternatives such a pure managed solution. But otherwise, i'd rather them focus on other stuff |
I recommend you visit some engineering blogs and leading open source http projects issue trackers to get a more accurate picture. Heck, go no further then StackOverflow to see they implemented their own websocket server (e.g NetGain) instead of using HttpListener WebSocket support (yes, they are running Windows 2012R2) http://nickcraver.com/blog/2016/02/17/stack-overflow-the-architecture-2016-edition/
Reliability is extremely difficult to assess until you go into production and it's virtually impossible if not politically risky to grade security. The more relevant concern I see coming from high traffic services is whether they can debug at this layer without taking additional dependencies on 3rd party components or waiting for a Microsoft patch. Putting it simply, the question is who are we marrying here .NET Core / .NET Core + LibUV / .NET Core + LibUV + Microsoft?
You are using the term "Network Stack" too loosely, I'm not talking about reimplementing the O/S TCP/IP Stack, The concern here is about two .NET Networking libraries that Microsoft has implemented and as far as .NET Http Client goes, it is implemented entirely in managed code in the "Full .NET FW" that you are using for years. The concern here is about the new implementation and lack of a managed socket based HttpListener in NET Core FX.
Times have changed, the level of interactivity has changed. People outside the .NET eco-system have been looking into these areas for several years now.
That's not the social contract in the open source community |
dotnet/corefx#10947 |
Triage: This is a long discussion about direction of the stack. It's not active anymore and it doesn't track any meaningful action item. Closing. If there are clear action items which are non-controversial, please let me know. |
So I wrote some test apps in C against LibUV and Libcurl api to get a feel of what’s powering Kestrel and HttpClient and while I can say that both libraries provide a very elegant and straightforward callback API I can’t help but raise the question:
Why do we need these in .NET Core?
Sure, LibUV makes perfect sense for NodeJS as a cross-platform abstraction layer for sockets, files, timers, thread pool, mutex.. but in .NET Core all these services are already inherently offered cross-platform by CoreFX. Simply put what does uv_accept / uv_read_start provide that the Socket.AcceptAsync/Socket.ReceiveAsync lack?
As for Libcurl, again great library for Native developers but what’s in it for Managed developers?
Furthermore, from what I see we are not using the high performance event driven curl_multi_socket_action interface with timeout callback and in any case why not just port the full .NET HttpWebRequest to use .NET Core cross-platform async socket interface and have a consistent implementation across both Windows / *Unix down to the socket level?
There is also a potential problem if someone wants to use a third-party native library (PInvoke) that depends on some version specific build of one of these; I mean how can you load multiple versions of LibUV or Libcurl in the same .NET process and why does the FW need to take part of any potential conflict that might occur?
Lastly, I think it's very important to include an equivalent of HttpListener for both Windows and *inux in CoreFX
Because:
The text was updated successfully, but these errors were encountered: