Closed frank-dspeed closed 3 months ago
hi @frank-dspeed. not sure what you are proposing exactly? a module for http/3 support? that would be nice to have for sure. not so sure if http/2 is worth implementing. also a bit iffy about how much complexity http/3 adds. one of the things that is great about http/1.1 is it is so easy to debug and hack on and you definitely can't say the same for http/3 and QUIC, but that is the way a large part of the industry seems to be moving.
am happy to help out in any way if you want to suggest a plan for putting this together. using a patched openssl library should be pretty straightforward. i have only implemented bare minimum crypto and tls functionality with openssl so far. i also did an mbedtls module that i can resurrect if that would be useful. crypto/security not really my area of expertise so would be good to have someone involved who could advise on best practice etc.
@billywhizz i total understand your point but there are methods to debug that one common way is to store the key in a unencrypted way via the handshake and log it then you can decrypt the traffic as usal with wireshark and so on.
Out of my View Quic is Essential for Security and i want to produce Micro Services with that. A TCP Requests makes About 4 Roundtrips that cost me CPU and RAM before i can choose if the Connection is valid. So http/3 solves that for me and i can reduce DDoS Attacks.
That sayed. Http/3 Includes http/2 but i do not plan to implement it indipendent. I do not plan to offer a JS API for the http/2 part but that can be done by some one else later if he needs that.
sounds good @frank-dspeed. if you want to discuss what's required let me know and i will help out whatever way i can. i'll see if i can get a change out in next week or so which will allow you to build an external module from a non just-js repo. it should be easy enough to set this up manually for now. will post some instructions later today if you haven't figured it out yourself.
are you thinking of implementing the http/2 protocol part in JS or using nghttp2 like node.js does?
@billywhizz i will use and algin with https://github.com/stefanocasazza/ULib
but i will also test to implement it with nghttp2 and maybe even rust- i need to look what performs better
@frank-dspeed have you looked at MSQuic at all? it seems like it might be a good candidate. will do some further research myself. https://techcommunity.microsoft.com/t5/networking-blog/making-msquic-blazing-fast/ba-p/2268963.
also, there are some working low level ffi bindings examples here. they might be useful if you are experimenting.
@billywhizz the ms stuff looks less performant as it uses openssl anyway under the hood https://microsoft.github.io/msquic/
but ya when it is easy integrate able it will do the job the first implementation doesn't need to be the best this is flexible enough to change that at anytime
Seems that HTTP/3 is supported by 97% of the browsers that support HTTP/2. (Including Safari behind a flag.) HTTP/2 is a multiplexing-streaming TCP protocol with prioritization & better header compression (never mind server push; few servers do that now anyhow, I could be interested, but that is a JustJS v2 IMHO).
I vote for HTTP/3 to be implemented first, HTTP/2 could be added later. Or the other way around? 🤷♂️ HTTP/1.1 is getting moldy ;)
@tomByrer the problem is there are a lot of implementations around and i am not sure which should finally be supported
also i am not sure if it even should be directly implemented or if it would be better to use something like haproxy => http
it will take time to figure out the right solution. do you got a idea which would be the best option?
got a idea which would be the best option
For HTTP/2 itself, or HTTP/3 vs 2?
I find Wikipedia has a decent listing of libraries for H3. I would believe those backed by corporations to be the most accurate & bug-free, though you could look at the fastest for inspiration. https://en.wikipedia.org/wiki/HTTP/3#Libraries
H2 is not so easy to narrow down. This one is patched by Cloudflare, whom I'm a fanboi of: https://github.com/hyperium/h2
I personally prefer https://github.com/h2o/h2o/ - it covers all three major HTTP versions and their development cycle is well managed, test-backed, performance-measurements backed (ultra low latency, ~linear multithreaded scaling), etc. It's also plain C, so it works "everywhere".
Anyway, just my two cents: https://github.com/cloudflare/quiche
@Wallacy this is really low level but i think it is really a nice thing to have it as low level alternativ.
But my feeling is that for rapid development maybe something with more features like h2 could be better or even the nginx one we should not under estimate that we can use anything to embedded v8 inside it.
so we can apply both directions to our code we can include inside v8 and call into the the lib but we could also integrate v8 as a lib and call into that.
The hard point is now to decide the right processing mode and even enable diffrent once like Apache WebServer Did it.
mpm-prefork, mpm-event, mpm-worker.
Ok good news SSL lib will be BoringSSL and we got a Rust Implementation that follows the standard and is deployed in production at cloudflare
Resources
Open Source Repos
Just a general note for no one in particular https://github.com/litespeedtech/lsquic is actively maintained https://en.wikipedia.org/wiki/HTTP/3#Implementations has a list of other potential implementations
I believe the best approach is to look at quic-interop-runner, at https://interop.seemann.io/ , where many http/3 library implementations are tested both on interoperability and performance.
Then you can make a more informed decision, by knowing all the options, their implementations and dependencies, as well as their expected performance.
from what i have looked at (not spent too much time on it), the MSFT Quic implementation seems to be the simplest and has a nice clean C api, which would be better for integrating with JS through bindings or FFI (which is now incredibly fast on JS, particularly V8).
One of the issues i have with most of the current implementations is they all want to take over the network interactions and/or the event loop, meaning we lose control from JS over non-blocking/async calls etc. If there is a set of QUIC/HTTP3 primitives available in library form that have nice clean C api's available and allow you to integrate your own event loop and network interfaces, please let me know.
The alternative of course would be to implement it from ground up in plain C/JS and engineer it specifically to integrate with and perform well embedded in JS, but this would be a pretty big undertaking.
Looking at the detailed implementations list, https://github.com/quicwg/base-drafts/wiki/Implementations , another possible candidate is picoquic
thanks @paulocoghi. yes, picoquic looks nice - i actually had it already starred but had forgotten about it. :sweat_smile:
this kinda relates to another dilemma i have with the Just-JS "approach". while v8 is incredibly fast and has tons of nice features and is incredibly well supported, it is becoming monstrously big as time goes on. i recently went from a version of v8 from may to the latest beta version and my runtime size went from ~23 MB to ~28MB :fearful:. The original Just-JS release from 2020 was 17MB).
I know QuickJS is an alternative and there are many other JS runtimes tailored for embedded systems, but none of them have JIT so performance on most tasks is orders of magnitude less than V8.
it may be possible to abstract away the interactions with the JS engine underneath and then build for different platforms using different JS engines. One of the nice things about the code i will be releasing is there is minimal C/C++ and most of the C/C++ is autogenerated from JS api definitions. You can see an early iteration of it here but it has changed a lot since then. I should be able to get the code out this week and hopefully there are some folks interested in discussing ways forward.
i recently went from a version of v8 from may to the latest beta version and my runtime size went from ~23 MB to ~28MB 😨. The original Just-JS release from 2020 was 17MB).
I believe this isn't a big problem, considering the notorious performance benefit. Also, you are a lot better than the executable size generated by Bun:
Command | Binary size | xz / gz / zip compressed | cold startup | warm startup | peak memory usage (binary) |
---|---|---|---|---|---|
bun build ./index.js --compile --outfile hello |
94M | 23M / 35M / 33M | 0.025s | 0.025s | 32.9M |
bkg -o hello . |
42M | 30M / 35M / 34M | 5.430s | 0.029s | 36.4M |
pkg -t node18-linux index.js |
45M | 13M / 18M / 17M | 0.115s | 0.116s | 38.5M |
I know QuickJS is an alternative and there are many other JS runtimes tailored for embedded systems, but none of them have JIT so performance on most tasks is orders of magnitude less than V8.
To this day, nothing can beat v8 and JSC. Even Spidermonkey can't (currently), but there are some experiments trying to create a runtime based on it (spiderfire).
IMHO, the only scenario where the performance would be (maybe) comparable when using lightweight JS implementations like QuickJS, is when all the heavy lifting (like http calls, filesystem, general I/O, etc) is made outside of JS.
This would bring faster startup times compared to JIT runtimes, and (maybe) comparable performance for everything (that matters).
Also, you are a lot better than the executable size generated by Bun:
i was gonna link https://github.com/oven-sh/bun/issues/2541, but looks like you've seen it :)
@leeoniya Great observation! Changing the unicode library to a lighter one can help a lot.
@billywhizz , do you think its feasible to replace v8's original unicode library to a lighter one, like icu4x?
@paulocoghi
i recently went from a version of v8 from may to the latest beta version and my runtime size went from ~23 MB to ~28MB 😨. The original Just-JS release from 2020 was 17MB).
yeah. all the other runtimes are huge and increasing rapidly as they add more "features". this is basically what i would like to avoid. a very small core that doesn't change very much over time and allows all the other things to grow on top of it. or not - maybe folks will only want to do low-level things with it. there was a big debate in node.js over this back in the early days and the "batteries included" folks won. probably why they are so popular now though. i'm not expecting anything done here to be competition for bun/node.js/deno - rather, an alternative approach.
if you want to bundle your app and all it's assets into a single static binary that also makes things smaller - usually by a few megabytes. so you should be able to get redistributable single binaries down to around ~25 MB at the lower end. it used to 16-17 MB not so long ago.
I have also done some experiments with bundling the application into a shared library, which can be loaded and run by the main spin runtime. these can be super tiny - a few hundred kilobytes as long as you have the runtime installed wherever you intend to run.
IMHO, the only scenario where the performance would be (maybe) comparable when using lightweight JS implementations like QuickJS, is when all the heavy lifting (like http calls, filesystem, general I/O, etc) is made outside of JS.
This would bring faster startup times compared to JIT runtimes, and (maybe) comparable performance for everything (that matters).
@paulocoghi yes, QuickJS can have fast bindings to C/C++ and can be fast if you can avoid writing much if any JS, but that wouldn't really work for what i am aiming for - i want folks writing more JS and only putting the minimum necessary code in C/C++/Rust land. with v8 fastcalls, the overhead into C++ from v8 JS is only ~2 nanoseconds which is negligible if you are doing mostly syscalls.
@leeoniya Great observation! Changing the unicode library to a lighter one can help a lot.
@billywhizz , do you think its feasible to replace v8's original unicode library to a lighter one, like icu4x?
@paulocoghi i haven't looked into Unicode much. It's not even bundling ICU at the moment so no Intl. I will have a look and see what this will add to size. but i think it could be easily made optional if you don't need it for your final build.
@leeoniya I can't believe what a small world this is. I used your dump_r
package for years until it stopped working. I know this is horribly off-topic but please consider updating it based on one of the many forks to make it php8 compatible, don't force me to use Symphony's lesser var_dump 🙏
don't force me to use Symphony's lesser var_dump 🙏
haha, don't force me to touch php again :D. i don't miss that dumpster fire or its lang committee's endless bikeshedding one bit.
I have also done some experiments with bundling the application into a shared library, which can be loaded and run by the main spin runtime. these can be super tiny - a few hundred kilobytes as long as you have the runtime installed wherever you intend to run.
Wow! Just wow! This seems an interesting approach! And I can already imagine Just/Spindle library becoming standard on major Linux distributions. Using it will be just an "apt-get/dnf install" away.
@billywhizz I sent you an email.
@paulocoghi
Wow! Just wow! This seems an interesting approach! And I can already imagine Just/Spindle library becoming standard on major Linux distributions. Using it will be just an "apt-get/dnf install" away.
yeah. one of the things i am looking at as i said is pretty much busybox but in JS. can also do really nice things with bundling like take your app and bundle it straight into an init which will be booted into in a VM. this should save some time off cold starts. i've done tons of mad experiments like this. the endpoint could be a whole linux distro completely written in JS, except for the kernel of course. you can also package your apps as vmlinux and have them run inside their own linux kernel from the shell.
is why i think exposing these lower level apis to JS without having lots of layers of abstraction could be a really nice feature. once you can get at those low level api's all sorts of new things become possible (from JS) and everything becomes a lot simpler and easier to reason about. imo anyway. :sweat_smile:
i also have an x86_64 machine code generator which i used for creating ffi bindings instead of relying on libffi, which imo is kinda clunky. let's make all the things JS and have some fun! :partying_face:
if nothing else, i think it would be a useful thing for experimentation and education. i've been really enjoying hacking on it.
Trying to enable Quic - http/3 draft.
Notes
Updates
Current Relevant Resources Readups
Ok good news SSL lib will be BoringSSL and we got a Rust Implementation that follows the standard and is deployed in production at cloudflare
Resources