I would love to hear some opinions from the authors of more contemporary web servers like one of H2O or Envoy. (The latter may have slightly different use cases though.)
I would love to hear some opinions from the authors of more contemporary web servers like one of H2O or Envoy. (The latter may have slightly different use cases though.)
NUMA is interesting, I've had a lot of fun with it on a system to control the adaptive mirrors in ESO's ELT telescope, and it is /amazing/ what you can do with a modern server, even on a vanilla kernel.
However, it is a lot harder to exploit NUMA in an application like Varnish, because the requests arrive as a randomized stream, and the effort to figure out which NUMA pool is best situated to handle the request, is not significantly different from just handling the request to begin with.
We used to serve a cache hit in seven system calls, an accept(2), a read(2), a write(2) and four timestamps, and as a result, Varnish servers ran with CPU's >70% idle.
If we had added NUMA-awareness on top of that, we would on average Nnuma-1/Nnuma of the time add at two system-calls to migrate the request to another NUMA domain, and that made little sense.
Since then NICs have become NUMA aware and since we use scatter/gather I/O, that matters a lot more than which CPU core did the overhead processing.
Where NUMA may become mandatory is 100G and 400G networking, but very few people seem interested in running that much traffic through a single server, for reasons of reliability, but I'm keeping an eye on it.
It will filter incoming TCP connections to listen sockets owned by threads bound to the same NUMA domain as the NIC that received the packets. This is part of the Netflix FreeBSD NUMA work described here https://papers.freebsd.org/2019/eurobsdcon/gallatin-numa_opt...
The idea is that you can keep connections local to a NUMA domain. We (Netflix) have a local patch to nginx to support this (basically just setting the socket ioctl on the listen socket after the nginx worker is bound)
As I said above, it is not obvious to me that we would gain much over what we already do, but I am keeping an eye on it.
But it is one of those things were I just chose to trust the OS to DTRT, and automatically reaped the benefits of advances "under the hood".
None of them go as fast as redbean of course. The blog post talks about how they only need 18 system calls to serve a local asset. redbean only needs one system call: writev(). That's because redbean cheats by having a novel design. The zip central directory means we don't need file system system calls. The invariant RDTSC instruction means we can also have timestamps without context switching.
Unless you are in numerical HPC or kernel programming, you do not need to think about NUMA, but it is not black/white, it is a slope.
Varnish tries to do certain things "NUMA-friendly", without actually being "NUMA-aware" as such, and the kernels seem to do a really good job with that.
In my opinion it’s about whether a software can process http requests on a configurable port - and envoy can for sure do that.
Regardless, calling envoy a webserver is misleading: it's both more and less, than a "traditional" webserver. It's a proxy; call it a proxy, please.
You can configure routes with a `direct_response` handler from envoy.yaml that is read from disk ;)