Kestrelhttpserver: Transport agnostic kestrel refactoring

Created on 11 May 2016  路  35Comments  路  Source: aspnet/KestrelHttpServer

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

3 - Done enhancement

Most helpful comment

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

All 35 comments

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

@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...

@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.

@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...

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

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?

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

@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).

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.

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

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

image

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

For those who might not have seen Bond, it's similar to protocol buffers but supports generics, transforms, metaprogramming, etc. No CoreCLR support yet: https://github.com/Microsoft/bond/issues/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.

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".

@davidfowl Move out of 1.1?

Yep

```c#
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; }
}
```

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

@davidfowl To use Pipelines?

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)

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?

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?

@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.

Agreed

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?

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.

Another question:

How does IHttpSendFileFeature fit in this abstraction?

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.

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

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).

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

@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?

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.

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.

Was this page helpful?
0 / 5 - 0 ratings