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

Developing an http server using libmill #161

Closed
arafath-mk opened this issue Aug 21, 2016 · 20 comments
Closed

Developing an http server using libmill #161

arafath-mk opened this issue Aug 21, 2016 · 20 comments
Labels

Comments

@arafath-mk
Copy link

arafath-mk commented Aug 21, 2016

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
Copy link
Contributor

raedwulf commented Aug 21, 2016

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
Copy link
Contributor

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

@sustrik
Copy link
Owner

sustrik commented Aug 21, 2016

Done!

@arafath-mk
Copy link
Author

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
Copy link
Contributor

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:

  • a proxy front-end for communicating with the backend web servers (translating between HTTP/2 and HTTP/1.1 if required). nghttpx is such an example for nghttp2.
  • communication between frontend and backend is done using IPC (pipes, unix sockets, shared memory etc.).
  • the backend servers can work as a limited frontend (e.g. you don't want to have proper proxying support for multiple backends but just want a simple webserver for an embedded system).

@arafath-mk
Copy link
Author

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
Copy link
Contributor

raedwulf commented Aug 21, 2016

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

  • 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: TLS Support #152 (comment)
  • Design an API for a HTTP/2 lib[md]ill-based library.
    • Keep in mind composability: Stream Channels? libdill#8 (comment)
    • The idea is that the API should be able to be able to expose a push interface (like wsock).
    • This is different to nghttp2 but having a list of what needs to be exposed could be useful from nghttp2's header.
    • Try and avoid kitchen-sink API design like nghttp2 as we assume we have coroutines and basic I/O supplied by libmill and libdill.
    • This will bubble up a parameter in the push functions to have a deadline.
    • If possible avoid callbacks to fit in with libmill/libdill design.

@arafath-mk
Copy link
Author

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
Copy link
Contributor

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
Copy link
Author

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
Copy link
Contributor

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: #152 (comment)

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
Copy link
Contributor

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
Copy link
Author

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

@raedwulf
Copy link
Contributor

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
Copy link
Author

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
Copy link
Contributor

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
Copy link
Author

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
Copy link
Owner

sustrik commented Dec 17, 2016

Closing old issues.

@sustrik sustrik closed this as completed Dec 17, 2016
@ubergarm
Copy link

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
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants