[HN Gopher] Mummy - web server written in Nim that returns to th...
___________________________________________________________________
Mummy - web server written in Nim that returns to the ancient ways
of threads
Author : michaelsbradley
Score : 76 points
Date : 2022-12-31 02:56 UTC (20 hours ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| elcritch wrote:
| I've been watching this one. It could be handy for embedded where
| it'd be nice to have a lightweight combined html/websocket
| server.
| nhatbui wrote:
| Also in microservices land you could have the service doing its
| business logic but needing to support a server for metrics
| and/or debugging. Just piling on, this is good to study :)
| forgotmypw17 wrote:
| Respect for supporting HTTP/1.0
| darthrupert wrote:
| This is great! Async still has its place for extremely low
| latency requirements, but threads should be good enough for
| almost every problem.
| iroddis wrote:
| What kind of latency are you talking about? Async latency for
| completing a task isn't deterministic, and there's no guarantee
| data will be processed as soon as it becomes available. Async
| runtimes rely heavily on hints from their tasks as to when to
| poll next.
|
| 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).
| zamalek wrote:
| What? The known/accepted tradeoff of async is gaining
| scalability (max concurrent connections) at the cost of
| latency.
| andrewstuart wrote:
| Those who view the source code will surely die of the curse.
| [deleted]
| isthisthingon99 wrote:
| Off-topic, but isn't the consensus that deaths related to
| opening of the tombs are caused by some bacteria?
| danparsonson wrote:
| They were entirely coincidental
| (https://en.m.wikipedia.org/wiki/Curse_of_the_pharaohs).
| skocznymroczny wrote:
| I bet it's just a one big wrapper anyway
| j16sdiz wrote:
| It is ok-ish, given how low level nim is.
| xigoi wrote:
| Woooosh
| daper wrote:
| Varnish (HTTP caching only) also uses one thread per client. I
| believe worker threads are used to handle reuqests while a
| dedicated thread handles all the idle connections between
| requests using epoll(). Also per-threads stack size is lowered so
| thousands of threads don't occupy massive amount of memory.
|
| 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.
| habibur wrote:
| Thought nginx epolls file i/o too along side socket i/o. Or did
| you find that the first call to open() or stat() stalls, while
| read/write after that continues normally?
| rkeene2 wrote:
| I wrote an extremely fast static HTTP server for this purpose
| [0].
|
| [0] https://filed.rkeene.org/
| metadat wrote:
| Off-topic: What happened to rkeene1?
|
| btw I really appreciate the design of you site, it's simple,
| clean, and beautiful. Timeless.
| v0idzer0 wrote:
| This thread model is actually similar to the approach that
| Node.js takes in using libuv as a thread pool. There's a main
| thread listening for incoming requests that immediately offloads
| the handling of them to the next available thread in the pool. Of
| course the handler thread can also offload some of its internal
| work to other pool threads.
|
| 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.
| vlovich123 wrote:
| I believe that you can also have multiple threads accepting
| connections on the same fd. This lets the kernel do the
| scheduling which removes the need for a coordinator thread. You
| can then choose to handle the connection on the same thread
| pinned to a specific CPU (per-cpu) or have a cross-thread task
| queue that whatever CPU is idle can handle (work stealing).
| tomphoolery wrote:
| There's also the process worker pool model, in which a master
| process forks a number of worker processes to handle all
| requests. Unicorn (for Ruby) does things this way...in part
| because when it was released, Rails apps couldn't handle
| multithreading all that well. I think Ruby also had some
| trouble with it, so this was just the easiest/most predictable
| way of getting good performance out of your Rails app.
|
| 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)
| masukomi wrote:
| ruby only had green threads until recently. If you actually
| wanted separate parallel work you had to fork.
___________________________________________________________________
(page generated 2022-12-31 23:01 UTC)