Skip to content
This repository has been archived by the owner on Dec 18, 2018. It is now read-only.

Transport agnostic kestrel refactoring #828

Closed
11 tasks
davidfowl opened this issue May 11, 2016 · 35 comments
Closed
11 tasks

Transport agnostic kestrel refactoring #828

davidfowl opened this issue May 11, 2016 · 35 comments

Comments

@davidfowl
Copy link
Member

davidfowl commented May 11, 2016

We want to allow a future where it is possible to use different transports:

image

We'll want to look at RIO, and PacketDirect (on windows) and libuv and .NET sockets.

SocketInput is a bit of a misnomer, it's really just a linked list of memory pool blocks that can be iterated using the MemoryPoolIterator.

Changes:

  • - Introduce ITransport interface that lives on KestrelServerOptions
  • - Decouple connection filters from libuv connection
  • - Rename Libuv related code into Libuv* named classes (Connection etc)
  • - Remove FrameContext from Frame inheritance hierarchy
  • - Remove FrameFactory from ServiceContext
  • - Refactor SocketInput
    • - Rename SocketInput to BufferChannel (or a better name if we come up with one)
    • - Introduce IWriteableBufferChannel and IReadableBufferChannel interfaces
  • - Remove IConnectionControl
  • - Change Frame to use IWriteableBufferChannel for output and IReadableBufferChannel for input.
  • - Make transport and connection filter consume and produce into IWriteableBufferChannel and IReadableBufferChannel

/cc @benaadams

@davidfowl davidfowl added this to the 1.0.0 milestone May 11, 2016
@tmds
Copy link
Contributor

tmds commented May 11, 2016

Would be nice if 'Transport' could be re-used in other server programs.

@davidfowl
Copy link
Member Author

@tmds I don't think that's valuable as a first class thing in Kestrel. The transport layer should be able to plug into kestrel but it's not going to be designed with general usability in mind. For that I'd suggest using the transport directly...

@tmds
Copy link
Contributor

tmds commented May 12, 2016

@davidfowl Even per transport, making it re-usable (if possible) may be nice. For example, if I want to write an RTSP server and use libuv, probably there is much interesting code in Kestrel. I understand that the scope is limited to Kestrel at this point and I haven't looked at what managed wrappers exist for rio, libuv and PacketDirect.

@MaherJendoubi
Copy link

@tmds Kestrel is intended to be a production HTTP(S) server for ASP.NET Core and it's not intended to be a fully-featured web server or a generic libuv .NET server or wrapper. It's recommended that you run it behind a more fully-featured web server, e.g. NGNIX, IIS...

@khellang
Copy link
Contributor

FYI; there's a spike of System.Net.Libuv in corefxlab; https://github.com/dotnet/corefxlab/tree/master/src/System.Net.Libuv

@aL3891
Copy link

aL3891 commented May 12, 2016

ooo big thumbs up from me, this would be really nice, I've been looking at running kestrel on top of Ripsharp but I've been holding off until RC2 (and the tooling) drops. This would make that a while lot easier.

I know there has been discussions of this before but then the consensus was that kestrel was too libuv specific and that generalizing it might make low level optimizations with libuv more difficult. what prompted this change of heart?

@davidfowl
Copy link
Member Author

We think we know how to do it now. Given the last year of experience and all of the refactoring we've done.

@dasMulli
Copy link

@davidfowl @tmds Have seen quite a bunch of hacky transport abstractions for SIP / RTSP / RTP implementations so some reusability would be nice in the long run (System.Net.Libuv looks promising).

@muratg muratg modified the milestones: Backlog, 1.0.0, 1.0.1 May 18, 2016
@davidfowl
Copy link
Member Author

Time to get more specific on this item. I've done a bunch of experiments in https://github.com/aspnet/KestrelHttpServer/tree/davidfowl/experiments and it's time to bring them back into kestrel in a sane way. This branch has tons of refactoring and the goal here is the pick them off and redo them in the main branch so we don't regress performance or functionality.

@davidfowl
Copy link
Member Author

This has morphed into https://github.com/davidfowl/Channels and will likely be brought back into kestrel.

@sqmgh
Copy link

sqmgh commented Sep 1, 2016

That's really cool, seems like something the Bond guys might be interested in too.

@rynowak
Copy link
Member

rynowak commented Sep 1, 2016

image

@sqmgh
Copy link

sqmgh commented Sep 1, 2016

I originally meant the Microsoft serialization project, but now I choose to believe that you guys have 00s running around the ASP offices!

@jongalloway
Copy link

For those who might not have seen Bond, it's similar to protocol buffers but supports generics, transforms, metaprogramming, etc. No CoreCLR support yet: microsoft/bond#166

https://github.com/Microsoft/bond

Bond is a cross-platform framework for working with schematized data. It supports cross-language de/serialization and powerful generic mechanisms for efficiently manipulating data. Bond is broadly used at Microsoft in high scale services.

@sqmgh
Copy link

sqmgh commented Sep 2, 2016

It sort of has CoreCLR support; I've been using it just fine for the most part. It's just the Unsafe package that isn't compatible due to native code issues with Streams. Of course this means there is no support for Streams.

So for now I just have an #IF def for CoreCLR that does the work into a regular buffer, and then wraps that into a stream manually. Terribly memory inefficient, but the code isn't in production yet so for now it's "good enough".

@muratg
Copy link
Contributor

muratg commented Sep 23, 2016

@davidfowl Move out of 1.1?

@davidfowl
Copy link
Member Author

Yep

@muratg muratg modified the milestones: 2.0.0, 1.1.0 Sep 23, 2016
@halter73 halter73 assigned halter73 and unassigned davidfowl Nov 22, 2016
@halter73
Copy link
Member

halter73 commented Jan 31, 2017

interface ITransportFactory
{
    ITransport Create(ListenOptions listenOptions, IConnectionHandler handler);
}

interface ITransport
{
   // Can only be called once per ITransport
   Task BindAsync(); 
   Task UnbindAsync();
   Task StopAsync();
}

interface IConnectionInformation
{
    IPEndPoint RemoteEndPoint { get; }
    IPEndPoint LocalEndPoint { get; }
}

// Implemented by Kestrel
interface IConnectionHandler
{
    IConnectionContext OnConnection(IConnectionInformation connectionInfo, PipeOptions inputOptions, PipeOptions outputOptions);
}

interface IConnectionContext
{
    string ConnectionId { get; }
    IPipelineWriter Input { get; }
    IPipelineReader Output { get; }
}

@davidfowl
Copy link
Member Author

@pakrym @halter73 we should also update the connection adapter interface.

@halter73
Copy link
Member

halter73 commented Feb 6, 2017

@davidfowl To use Pipelines?

@davidfowl
Copy link
Member Author

Yes, it needs to do 2 things:

  • Change from being Stream to being pipelines
  • Add a enum to the context so that kestrel knows what protocol to use (http2 http, https)

@Drawaes
Copy link
Contributor

Drawaes commented Feb 8, 2017

Careful there, if you have (http2, http, https) do you then need http2 over https? are you defining the highest level protocol in the stack?

@davidfowl
Copy link
Member Author

Nobody supports http2 is always over https 😄 . We might need another way to set the scheme. So http and http2 and then a scheme property?

@cesarblum
Copy link
Contributor

@davidfowl I think that's better factored. Putting http, http2 and https in the same category mixes things up, since https means one of the other two over TLS.

@Drawaes
Copy link
Contributor

Drawaes commented Feb 8, 2017

Agreed

@tmds
Copy link
Contributor

tmds commented Feb 27, 2017

ITransport Create(ListenOptions listenOptions, IConnectionHandler handler);

@halter73 Some questions:

When providing multiple ASPNETCORE_SERVERURLS would these create multiple Transports? If they are handled by the same transport this could be more efficient. Then the listenOptions should be an array.

In the current implementation, Kestrel starts a number of threads to accept incoming requests. Will this become the responsibility of ITransport? Will you provide information about the number of threads that the Transport should create?

@davidfowl
Copy link
Member Author

In the current implementation, Kestrel starts a number of threads to accept incoming requests. Will this become the responsibility of ITransport? Will you provide information about the number of threads that the Transport should create?

This will become transport specific configuration.

@tmds
Copy link
Contributor

tmds commented Feb 27, 2017

Another question:

How does IHttpSendFileFeature fit in this abstraction?

@davidfowl
Copy link
Member Author

How does IHttpSendFileFeature fit in this abstraction?

That's a good question, it doesn't fit today. Connection filters can add http features but transports can't, we should fix that.

@Tratcher
Copy link
Member

With this layering how does IHttpSendFileFeature work over SSL? Also chunking.

@davidfowl
Copy link
Member Author

That's why we directly implement send file in kestrel previously 😄 . I still think we should allow transports to manipulate features per request (like connection filters can).

@Drawaes
Copy link
Contributor

Drawaes commented Feb 27, 2017

Like my ntlm/kerb adapter... needs to be able to change a feature on the request

@tmds
Copy link
Contributor

tmds commented Mar 1, 2017

@davidfowl don't know if you saw this question:

When providing multiple ASPNETCORE_SERVERURLS would these create multiple Transports? If they are handled by the same transport this could be more efficient. Then the listenOptions should be an array.

And another question:
What's the difference between UnbindAsync and StopAsync? Is UnbindAsync: close listen sockets and StopAsync: close client sockets?

@davidfowl
Copy link
Member Author

When providing multiple ASPNETCORE_SERVERURLS would these create multiple Transports? If they are handled by the same transport this could be more efficient. Then the listenOptions should be an array.

It's a transport per binding with the current design.

What's the difference between UnbindAsync and StopAsync? Is UnbindAsync: close listen sockets and StopAsync: close client sockets?

Yes.

@tmds
Copy link
Contributor

tmds commented Mar 1, 2017

It's a transport per binding with the current design.

It may be more efficient to leave it up to the Transport on how it handles multiple listeners. A Thread created by a Transport may be capable of handling multiple listeners. If each Transport creates it's own listener threads, this will cause unnecessary context switching.

halter73 added a commit that referenced this issue Mar 29, 2017
- Add transport interfaces
- Create separate Core and Libuv projects

#828
@halter73 halter73 closed this as completed Apr 3, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests