sustrik / libmill

Go-style concurrency in C
MIT License
2.74k stars 204 forks source link

Developing an http server using libmill #161

Closed arafath-mk closed 7 years ago

arafath-mk commented 8 years ago

I would like to develop an http server using libmill. As a first step, I am planning to port an existing go based http server library using libmill. (https://github.com/valyala/fasthttp) Is it a good idea? Will I get more performance than Go? (I am expecting more performance since this web server will be in C)

I hope, the porting will be easy as there is 1:1 mapping of concurrency model. And I would like to port this (new webserver) code to libdill once it is matured.

raedwulf commented 8 years ago

Excellent idea! I'm looking at developing a http/2 server using nghttp2 (so that the hardwork is done for me already). However, nghttp2 does not support http/1.1.

It should, in theory, be faster. My preliminary microbenchmark helloworld put a nghttp2 server (with single thread/1 stream) only 20% behind lwan which arguably is the fastest web server for raw-http/1.1 serving. This is with lwan's highly optimised http parsing implementation etc. whereas http2 is a more complicated protocol and nghttp2's implementation has been aiming for correctness rather than raw performance (as yet). See #155.

In terms of the performance from actual libmill features that will be pitted against go, namely co/goroutines, HEAD has an x86-64 assembler implementation of the context switching. To compare use this code:

https://github.com/jamel/go-perf-tests

On my Intel(R) Core(TM) i3-5010U CPU @ 2.10GHz for go:

$ ./ctxswitch 10
performed 10M context switches in 3.101000 seconds
duration of one context switch: 310 ns
context switches per second: 3.225806M

On my Intel(R) Core(TM) i3-5010U CPU @ 2.10GHz for git libmill:

$ ./ctxswitch 10
performed 10M context switches in 0.289000 seconds
duration of one context switch: 28 ns
context switches per second: 35.714283M

On an older Intel(R) Pentium(R) Dual CPU T2370 @ 1.73GHz, libmill gets:

$ ./perf/ctxswitch 10
performed 10M context switches in 0.420000 seconds
duration of one context switch: 42 ns
context switches per second: 23.809525M

Which basically makes context switching costs almost negligible across x86-64 platforms! The implementation of the context switching may even be faster than lwan's due to inlining... but I haven't tested this.

raedwulf commented 8 years ago

@sustrik Can you tag these issues as "questions" on github.

sustrik commented 8 years ago

Done!

arafath-mk commented 8 years ago

The application server should work in all major browsers. Can nghttp2 handle requests from http/1.1 clients? What about support for SSL and WebSockets? Do we need to focus on porting https://github.com/valyala/fasthttp or nghttp2 ?

raedwulf commented 8 years ago

The application server should work in all major browsers. Can nghttp2 handle requests from http/1.1 clients?

nghttp2 does not handle http/1.1 requests, but fasthttp doesn't handle http/2 requests either.

What about support for SSL and WebSockets?

Support for ssl/tls is ongoing: #152 This is necessary for HTTP/2 to function in browsers but you can still use some tools to test non-SSL/TLS http/2 web servers while under development. I saw some of @sustrik 's repositories have websocket support... I don't know their status though. Leave that extension for another day as websockets don't actually have much relationship with the webserver itself and can be implemented independently.

Do we need to focus on porting https://github.com/valyala/fasthttp or nghttp2 ?

nghttp2 doesn't need porting, just needs a libmill backend and a new frontend unless you want to reimplement it from scratch (to better integrate http/1.1, http/2 and libmill under a cohesive API). Don't worry about that for now, I'm currently working with nghttp2 for a basic web-server so better focus on fasthttp or some http/1.1 implementation first.

Use cases In terms of use cases, HTTP/2 is well-supported in browsers now but there's not many implementations out there. HTTP/1.1 is still required for some older browsers and mobile browsers that don't get the love they need.

Eventual Architecture? As you intend to port it to libdill, I think @sustrik had ideas of protocol layering and having a separate libdill-based library that implement protocol primitives. So something for a HTTP server would end up like a series of layers: dsocks (TCP/IP) <-> dsocks (TLS) <-> dnetproto (HTTP/1.1 or HTTP2).

In my mind, I envisioned a complete web server to involve a series of binaries (to follow the UNIX principle). Main points are:

arafath-mk commented 8 years ago

In terms of use cases, HTTP/2 is well-supported in browsers now but there's not many implementations out there. HTTP/1.1 is still required for some older browsers and mobile browsers that don't get the love they need.

Most of the modern JavaScript libraries/frameworks don't work in older browsers. So, now a days, web application developers focus on relatively new browsers only. So, it is a good idea to focus on HTTP/2.

I'm currently working with nghttp2 for a basic web-server

How can I help you now? Or do you have any other tasks in your mind for me?

raedwulf commented 8 years ago

I'm currently busy for the next 10 days or so but the initial tasks that need to be done for HTTP/2 are:

arafath-mk commented 8 years ago

Implement a TLS API into libmill. There's some basic SSL support in the repository already but it lacks ALPN (required) and SNI (desirable) extensions. I wrote a preliminary API design for: #152 (comment)

SSL, ALPN and SNI are new to me for implementing. So, I need to get familiarize to those at first. Your help/guidance is appreciated.

Design an API for a HTTP/2 lib[md]ill-based library.

Here too, I need to get familiarize things at first.

raedwulf commented 8 years ago

SSL, ALPN and SNI are new to me for implementing. So, I need to get familiarize to those at first. Your help/guidance is appreciated.

We were thinking that the best approach would be to port the code from libtls and link with openssl/libressl, whichever is available on the target system. https://github.com/libressl-portable/openbsd/tree/master/src/lib/libtls

arafath-mk commented 8 years ago

https://github.com/libressl-portable/openbsd/tree/master/src/lib/libtls

  1. How to build the current libtls in Linux ?
  2. What is to be done next? (Do we need to use libmill APIs for I/O operations in libtls ?)
raedwulf commented 8 years ago

How to build the current libtls in Linux ?

If your distribution has libressl, libtls is built along with it. For example see: https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=libressl

What is to be done next? (Do we need to use libmill APIs for I/O operations in libtls ?)

Pretty much and matching the API in the similar way to the one I gave here: https://github.com/sustrik/libmill/issues/152#issuecomment-236185139

If your distribution uses OpenSSL, some of the headers will be different to libressl (distinguish using an #ifdef). If you use the latest beta OpenSSL 1.1, it is NOT backwards compatible - again use appropriate #ifdef statements if required. The priority would be OpenSSL 1.0.2 and libressl compatbility. ALPN support is unavailable prior to OpenSSL 1.0.2 so disable those features/ignore parameters when required.

P.S. There may be mistakes in the API, but the general idea is there.

raedwulf commented 8 years ago

I am lurking on IRC: ##libmill on freenode today if anyone wants a quick chat. Yes, double hashes, as it's not an official channel.

arafath-mk commented 8 years ago

Thanks. IRC will be helpful. I was busy today. See you there in coming days.

raedwulf commented 8 years ago

There's a node.js implementation; https://github.com/molnarg/node-http2

Node.js also uses asynchronous I/O calls so in theory some of the design concepts from that implementation could be useful.

arafath-mk commented 8 years ago

Normally Node.JS modules have tones of dependencies with other modules (directly or indirectly). So, I think, it would be better to refer a C/C++ implementation.

raedwulf commented 8 years ago

Although perhaps implementing it directly from the RFC would be better, then we have a full understanding of the quirks, performance etc. https://tools.ietf.org/rfc/rfc7540.txt

arafath-mk commented 8 years ago

I think, referring both RFC and a working C implementation would be better. What about H2O server? https://h2o.examp1e.net/

Meanwhile, I am familiarizing the afore mentioned technologies and doing some research on network and file access performance improvement.

My primary focus on Performance and Scalability.

sustrik commented 7 years ago

Closing old issues.

ubergarm commented 7 years ago

Has anyone made some progress in implementing a libmill+dsock HTTP server / webframework?

I've been fooling with it, but haven't gotten too far. My poor, unoptimized, incorrect toy implementation isn't going as fast as I'd hoped. hahaha...

Anecdotal toy benchmarks are here: https://github.com/ubergarm/binks

Any pointers or more dsock example code that handles requests, responses, and message body would be useful. Cheers!

ubergarm commented 7 years ago

The saga continues! Pretty sure my benchmarks were way off because wrk was using KeepAlive and recycling TCP connections for some webframeworks I tested, thus not accurately reflecting libdill+dsock's abilities.

I scratched everything and will try some more.

Gonna earn my grey hairs trying to figure this stuff out... ;)