Mummy – web server written in Nim that returns to the ancient ways of threads
github.com
github.com
What other server thread models exist? I know php-fpm gives each request it’s own process, but I can’t think of any other feasible strategies off the top of my head.
Originally, the way `php-fpm` works is pretty much how the entire web worked. Every request into a server would go through `inetd`, it would fork a handler process, and the request would respond when the process exited. This became very difficult to handle at scale, mostly because of the overhead for forking a process, so the next logical step is to have a pool of worker processes ready to go in order to immediately receive requests. This is great for applications that don't need to get redeployed very often, but as we moved into more of a continuous deployment workflow, it began to break down as worker processes would need to be restarted, going back to that whole "overhead" thing. Unicorn suffers from this problem a bit, if you try to `SIGHUP` and reload application code when workers are still processing requests, Unicorn will wait until those processes have finished responding to restart the process and load the new version. If a client is taking too long and hanging onto the process, it's very possible that the process will just never reload the code and you'll have weird errors happening every so often.
A solution to this problem is to move this pool of worker processes into a pool of threads, which allow the server to control a bit more about how the application code is reloaded, and not have to deal with the overhead of forking processes. I believe that's how NGINX, Node.js, Puma, et. al. work under the hood...there's a thread pool of workers and another thread that listens to requests. Everything is event-driven, so when a new event comes in, the listener thread just sends that event off to the pool of worker threads. Basically the same idea, but using an event loop as a model for better concurrency support. (Puma is a bit different because it does allow for worker processes in addition to threads, but this isn't necessary, it just allows for better performance on larger machines)
Single threaded HTTP servers have their own issues. If the bottleneck is the storage then lack of async open()/stat() and some other calls is problematic. We feel that serving hundreds of millions of files (long tail content) from slow storage using nginx. For that reason you can configure nginx to spawn multiple processes.
btw I really appreciate the design of you site, it's simple, clean, and beautiful. Timeless.
[0] https://www2.fossil-scm.org/home/doc/trunk/www/index.wiki
Those could however be offloaded onto a threadpool, to avoid the blocking to affect any other requests that are processed by the same Nginx worker. Nginx however only partially does that - whole file read and write operations are offloaded a whole bunch of other IO (stat, open, close) are executed on the main thread. I guess due to implementation challenges - one can’t just make one operation async but also needs to make each operation that utilizes those methods async.
./src/os/unix/ngx_file_aio_read.c
API's doc https://man7.org/linux/man-pages/man3/aio_read.3.html
Even though the source is there don't mean it's compiled or used though. Might or might not be. No idea about the details.
Generally, low latency means producing a result as soon as possible. Threads are ideal for that case, expending spinning cpu time for asap processing.
The best description I’ve heard of async is concurrent waiting, vs concurrent processing for threads (from the excellent zero2prod book).