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

Performant HTTP server #44

Open
brandonros opened this issue Sep 13, 2019 · 23 comments
Open

Performant HTTP server #44

brandonros opened this issue Sep 13, 2019 · 23 comments

Comments

@brandonros
Copy link

While I doubt nobody is rushing to run this in production, I am also going to bet that:

let conn;
while (true) {
    conn = await t.accept();
    handleConnection(conn);
    conn = undefined;
}

won't lead to the most performant approach to serving HTTP requests.

What are your thoughts on putting epoll or kqueue or select or something? How does libuv achieve this for servers?

@saghul
Copy link
Owner

saghul commented Sep 13, 2019

Hey there!

libuv uses epoll on Linux, kqueue on macOS and BSDs, IOCP on Windows, etc. What you see there is not a blocking call, everything continues to be async under the hood.

That said, I'm not (yet) focusing on servers. I was considering maybe using libwebsockets to do the heavy lifting, since it would provide HTTP (also HTTP/2) and WS so I could avoid having to do it myself, at least as a start :-)

@brandonros
Copy link
Author

libwebsockets is a good idea

could you outline what that would take and I’ll see if I can take a crack at it?

@saghul
Copy link
Owner

saghul commented Sep 14, 2019

Sure thing! So I think the approach would be similar to curl: use a bit submodule and make using the system version optional.

Then there would be one lws “context” per QUVRuntime, and poll handlers would be used. I took a quick look and lws supports libuv integration and “external loop” already so that’s pretty cool.

As for the JS API, I don’t know, but that can be iterated!

Cheers!

@brandonros brandonros mentioned this issue Sep 14, 2019
@brandonros
Copy link
Author

https://github.com/warmcat/libwebsockets/blob/master/test-apps/test-server.c

Are you able to mainly use that code?

I'm curious to hear what your usecase for quv is? You are clearly doing a great job fleshing it out and putting a bit of effort into it.

@saghul
Copy link
Owner

saghul commented Sep 23, 2019

https://github.com/warmcat/libwebsockets/blob/master/test-apps/test-server.c

Are you able to mainly use that code?

I'd say mostly yes. The important part is to use uv_poll_t handles to make sure the polling is handled by libuv. In addition, We probably want one per-runtime lws_server thing, see how we do it for the CURLM handle.

I'm curious to hear what your usecase for quv is? You are clearly doing a great job fleshing it out and putting a bit of effort into it.

I'm still figuring that out :-) For now I'm just having fun in the evenings and figuring things out as I go.

@brandonros
Copy link
Author

Compared to node.js, how bad do you think quv + libwebsocket performance would be for an HTTP server?

@saghul
Copy link
Owner

saghul commented Sep 27, 2019

It’s impossible to estimate because everything is different across the 2. QuickJS is a lot slower than V8 to begin with: https://bellard.org/quickjs/bench.html

@s0kil
Copy link

s0kil commented Nov 10, 2019

Another option could be to use uWebSockets

@saghul
Copy link
Owner

saghul commented Nov 10, 2019

Good one indeed! Does it also provide a C API or is it just C++?

@s0kil
Copy link

s0kil commented Nov 10, 2019

I'm not sure, but it is built somehow into a JavaScript wrapper: https://github.com/uNetworking/uWebSockets.js

This was referenced Mar 3, 2020
@srdjan
Copy link

srdjan commented May 20, 2020

in case you didn't look it up... uWebSockets is built on top of uSockets - which is a C API

txiki.js is a great, fun project - btw!!!

@lal12
Copy link
Contributor

lal12 commented Apr 13, 2024

@saghul I currently thinking about implementing a HTTP server for txiki. Though there are many different possibilities on how to approach this. E.g. libwebsockets is pretty large in itself and there would be different ways to integrate it. So did you have given this any thought already?

@saghul
Copy link
Owner

saghul commented Apr 13, 2024

Hey there! Yes, I have given it quite a bit of thought lately.

My current state of mind is that of going with libwebsockets + mbedtls.

Yes, lws is somewhat large, but it has built time knobs for almost everything, and since we'd vendor it, we can only compile what we need.

That can start with HTTP and WS servers.

I'm also choosing mbedtls so I can implement TLS sockets and the subtle crypto web API.

Ultimately it would probably be nice to also replace the HTTP and WS client code with lws, so use a single dependency, and to get rid of the mess that WS currently is 😅

@lal12
Copy link
Contributor

lal12 commented Apr 16, 2024

So I have a minimal prototypic implementation with libwebsockets running.
I don't think the libwebsockets API is a great fit. It's a bit dependent on the use case, but libwebsockets probably works great if you want basically a out of the box webserver for your project and just want to configure/adjust a few knobs. But my aim was more of a NodeJS like API where you have a basic API and to do the more advanced handling by yourself (or a library). This latter option however doesn't seem to be a good application for libwebsockets. Generally it is quite rigid, which is probably good for most cases, but not necessarily for a generic JS API. It's maybe a bit more framework than library.

Will give it a few thoughts, whether I continue with it or look at something else.

@saghul
Copy link
Owner

saghul commented Apr 16, 2024

Thanks for sharing!

@lal12
Copy link
Contributor

lal12 commented Apr 19, 2024

Currently working on a very minimal implementation based on llhttp (nodejs http parser) here: https://github.com/lal12/txiki.js/tree/add-http-server.

Performance wasn't the main focus, I generally think if that's really the focus, nodejs or an nginx reverse proxy (e.g. delivering assets and caching) is the way to go.

My first benchmarks (GET route returning 'hello world') showing 4-11k requests/s, compared to nodejs with 87k requests/s.

@saghul
Copy link
Owner

saghul commented Apr 19, 2024

Exciting! I'll take a look shortly! Going low level is also something I considered but wanted to avoid...

@lal12
Copy link
Contributor

lal12 commented Apr 20, 2024

Exciting! I'll take a look shortly! Going low level is also something I considered but wanted to avoid...

Tend to agree. uWebsockets actually looks good, though it would be C++. Another one on my list ist microhttpd though I haven't looked closer at it yet.

@saghul
Copy link
Owner

saghul commented Apr 20, 2024

IIRC uWS only supports OpenSSL, and I think it would be nice to use something smaller like mbedtls.

I have never used microhttpd. I see there are 2 projects with that name, one part of GNU and thus GPL which we can't use.

@lal12
Copy link
Contributor

lal12 commented Apr 20, 2024

Yeah forgot that it was GPL, that's why I never looked into microhttpd in detail in the first place.

@anggape
Copy link

anggape commented Apr 22, 2024

i think https://github.com/civetweb/civetweb is a good fit for this project. it meets all the requirements discussed earlier: MIT license, websocket client + server, mbedtls support, and small size

@saghul
Copy link
Owner

saghul commented Apr 22, 2024

Thanks for sharing!

@KaruroChori
Copy link
Contributor

KaruroChori commented Jun 8, 2024

Currently working on a very minimal implementation based on llhttp (nodejs http parser) here: https://github.com/lal12/txiki.js/tree/add-http-server.

Performance wasn't the main focus, I generally think if that's really the focus, nodejs or an nginx reverse proxy (e.g. delivering assets and caching) is the way to go.

My first benchmarks (GET route returning 'hello world') showing 4-11k requests/s, compared to nodejs with 87k requests/s.

I repackaged your code as an external module here: https://github.com/KaruroChori/http-txiki-module.
However, there are no examples on how to use it so I have not really tested it.

I will probably work a bit more on it to provide full ts types and some tests. The overall slowness of your benchmark aligns with the general gap in performance I also observed in other tasks.

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

No branches or pull requests

7 participants