4 ms·
Every web server claims to be fast, so I wonder how they define that. As someone who has written their own supposedly fast web server I only want configuration
by austin-cheney 2y ago
Every web server claims to be fast, so I wonder how they define that. As someone who has written their own supposedly fast web server I only want configuration simplicity. Most web servers are unnecessarily far too complicated.
In a web server here is what I am looking for:
* Fast. That is just a matter of streams and pipes. More on this later. That said the language the web server is written in largely irrelevant to its real world performance so long as it can execute low level streams and pipes.
* HTTP and WebSocket support. Ideally a web server will support both on the same port. It’s not challenging because you just have to examine the first incoming payload on the connection.
* Security. This does not have to be complicated. Let the server administrator define their own security rules and just execute those rules on incoming connections. For everything that fails just destroy the connection. Don’t send any response.
* Proxy/reverse proxy support. This is more simple than it sounds. It’s just a pipe to another local existing stream or piping to a new stream opened to a specified location. If authentication is required it can be the same authentication that sits behind the regular 403 HTTP response. The direction of the proxy is just a matter of who pipes to who.
* TLS with and without certificate trust. I HATE certificates with extreme anger, especially for localhost connections. A good web server will account for that anger.
* File system support. Reading from the file system for a specific resource by name should be a low level stream via file descriptor piped back to the response. If this specific file system resource is something internally required by the application, like a default homepage it should be read only once and then forever fetched from memory by variable name. Displaying file system resources, like a directory listing, doesn’t have to be slow or primitive or brittle.
- xorcist 2y agoMost of these things are much harder to get right that you make it sound. Perhaps proxying most so. It is a legitimately hard problem. Look at something like Varnish, which is likely one of the better proxies out there. It took many years to get good. I never had to write a proxy and am grateful for it. You have to really understand the whole network stack, window sizes and the effects of buffering, what to do about in flight requests, and so on. Just sending stuff from the file system is comparatively easier where you have things such as sendfile, provided you get the security implications of file paths right.
- koakuma-chan 2y agoIn Rust all web frameworks are fast because they all use the same stack tokio + hyper.
- dorianniemiec 2y agoBy the way, Ferron web server also uses Tokio and Hyper.
- cle 2y agoHold my beer while I trivially write a slow web server on tokio + hyper.
- alexpadula 2y agoHolding :>
- 01HNNWZ0MV43FF 2y agoI could write one without Tokio, I'd just poll the sockets at 100 Hz
- cle 2y agoWhy not two birds with one stone: do the same in tokio + hyper, and disprove the ridiculous claim!
- ninkendo 2y agoFun experiment, try and benchmark a simple file download on a simple web server using rocket.rs (which also uses tokio and hyper, and has a built in fileserver type, so just a few lines of code) and compare it to a vanilla nginx config. Here’s the rocket.rs source I used: #[rocket::main] async fn main() -> Result<(), rocket::Error> { rocket::build() .mount("/", rocket::fs::FileServer::from("/tmp/test")) .ignite() .await? .launch() .await?; Ok(()) } And do `mkdir /tmp/test && dd if=/dev/urandom of=/tmp/test/bigfile bs=1G count1` to create a 1G file, and run `time curl -o /dev/null localhost:8000/bigfile`. My nginx config: worker_processes auto; master_process off; pid /dev/null; events {} http { sendfile on; access_log /dev/stdout; error_log /dev/stderr; server { listen 8089; server_name localhost; root /tmp/test; location / { try_files $uri $uri/ =404; } } } launched with `nginx -c "$(pwd)"/nginx.conf -g "daemon off;"` The results for a 1GB file for me on an nvme ssd, averaged over 100 runs: nginx: 150ms rocket: 4 seconds Or roughly 25x slower. Release mode makes no difference. You can definitely write slow code in rust if you’re naive about reading/writing between channels a few kilobytes at a time, which is what rocket does, vs using sendfile(2), like nginx does. Edit: These numbers were from a few months ago... I tried it again by just pasting the above into a new project with `cargo init` and adding rocket and tokio to my deps, and it's now 2.3s in debug and 1.2s in release mode. It may have improved since a few months ago, but it's still 10x slower.
- MaxBarraclough 2y ago> Fast. That is just a matter of streams and pipes. More on this later. That said the language the web server is written in largely irrelevant to its real world performance so long as it can execute low level streams and pipes. I'm no expert, but that doesn't sound right to me. Efficiently serving vast quantities of static data isn't trivial, Netflix famously use kernel-level optimisations. [0] If you're serious about handling a great many concurrent web-API requests, you'll need to watch your step with concerns like asynchrony. Some languages make that much easier than others. Plenty of work has gone into nginx's efficiency, for example, which is highly asynchronous but is written in C, a language that lacks features to aid with asynchronous programming. If you aren't doing that kind of serious performance work, your solution presumably isn't performance-competitive with the ones that do. As you say, anyone can call their solution fast. [0] [PDF] https://freebsdfoundation.org/wp-content/uploads/2020/10/netflixcasestudy_final.pdf https://freebsdfoundation.org/wp-content/uploads/2020/10/net...
- pas 2y agoeveryone is using kernel optimisations at that size. (because it's worth it, because there's a well known pattern of load, file/chunk sizes (so I/O in general) and metrics to shoot for) nginx is a big state machine built around epoll, and there's not much to do with the raw kernel ABI anyway (of course using safer and more powerful tools helps with the general quality of the end result, but not really with speed). it took many years for the uring ABI to emerge (and even using it efficiently is not trivial).
- 1dom 2y agoCan you share a link to your web server please? I'm finding it hard to make sense of your comment: I can't reconcile some of the stuff you're saying. My gut feeling is you're either ridiculously smart, so smart that defining and implementing a security rules engine for a web server is something genuinely trivial for you, and the world has a lot to learn from you. Or, you're really, really not aware of how much you don't know, so much so that you're going to end up doing something stupid/dangerous without realising. Either way, an example of a supposedly fast web server written by you should clear it up pretty quickly. Sorry, because this feels a little rude, and I don't mean it to be, but you're contradicting quite a lot of widely held common sense and best practise in a very blasé way, and I think that makes the burden of proof a little higher than normal.
- sim7c00 2y agoa rules engine for a web server isnt difficult if it doesnt have to carry responsibility for the web app security itself. then its as the posted outlined really... that being said, its common for new servers to have old vulns, not many coders will go over cve reports of apache and nginx and test their own code against old vulns in those. i do find a lot of claims about performance or security are oftend unsupported as with this server. it just says it on the readme but provides no additional contex or proof or anything to back up those claims. my thought is that original commenter gott riggered by that, perhaps rightfully, and points out thia fact more than anything. if you want to claim high performance or security, back it up with proof. the simple fact its in rust doesnt make it more secure. and using async in rust doesnt imply good performance. it could in both cases. wheres the proof.?
- dorianniemiec 2y agoRegarding the server performance, there are benchmark results on the Ferron's website.
- solatic 2y agoNot OP, and also not a web server genius, but I read OP's comment as allowing server administers to write policy in OPA then just using https://github.com/microsoft/regorus/ https://github.com/microsoft/regorus/ to determine whether to allow or forbid the connection. The web server author can clearly document what is available in input/data to be checked against in the policy. Is it really more complicated than that?
- gizmo 2y agoSecurity is not that simple. Duplicate HTTP headers, utf-8 in HTTP headers, case insensitivity etc has resulted in countless security vulnerabilities over the years. Do you reject suspicious requests? Do you process the request but filter out invalid headers? What about suspicious headers being returned from the app being served? You have to make choices here and if you choose unwisely bad things happen. The spec is of little help here, because web browsers and other web servers (and downstream app servers) don't adhere to the specs being sometimes too lenient and in other times too restrictive in what they do. Just take a look at https://www.rfc-editor.org/rfc/rfc9110#section-5.5 https://www.rfc-editor.org/rfc/rfc9110#section-5.5 to get an idea of how any choice made by a web server can blow up in your face.