Hacker News new | past | comments | ask | show | jobs | submit login

This is simply a wrong idea about how to write web servers. You're giving up scalability massively, only to gain a minor amount of safety - one that is virtually irrelevant in a memory safe language, which you should anyway use. The overhead of process-per-request, or even thread-per-request, is absurd if you're already using a memory safe language.





> You're giving up scalability massively

you’re vastly over estimating the overhead of processes and number of simultaneous web connections.

> only to gain a minor amount of safety

What you’re telling me is performance (memory?) is such a high priority you’re willing to make correctness and security tradeoffs.

And I’m saying thats ok, one of those is crashing might bring down more than one request.

> one that is virtually irrelevant in a memory safe language

Your memory safe language uses C libraries in its process.

Memory safe languages have bugs all the time. The attack surface is every line of your program and runtime.

Memory is only one kind of resource and privilege. Process isolation is key for managing resource access - for example file descriptors.

Chrome is a case study if these principles. Everybody thought isolating JS and HTML pages should be easy - nobody could get it right and chrome instead wrapped each page in a process.


Please find one web server being actively developed using one process per request.

Handling thousands of concurrent requests is table stakes for a simple web server. Handling thousands of concurrent processes is beyond most OSs. The context switching overhead alone would consume much of the CPU of the system. Even hundreds of processes will mean a good fraction of the CPU being spent solely on context switching - which is a terrible place to be.


> Handling thousands of concurrent processes is beyond most OS

It works fine on Linux - the operating system for the internet. Have you tried it?

> good fraction of the CPU being spent solely on context switching

I was waiting for this one. Threads and processes do the same amount of context switching. The overhead of processes switch is a little higher. The main cost is memory.


> Threads and processes do the same amount of context switching.

Yes, therefore real webservers use a limited amount of threads/processes (in the same ballpark as a number of CPU cores). Modern approach is to use green threads which are really cheap to switch, it is like store registers, read registers and jmp.

> The main cost is memory.

The main cost is scheduling, not switching per se. Preemptive multitasking needs to deal with priorities to not waste time, and algorithms that do it are O(N) mostly. All these O(N) calculations needs to be completed multiple times per second, the higher the frequency of switching the more work to do. When you have thousands of processes it is the main cost. If you have tens of thousands it starts to bite hard.


> The main cost is scheduling, not switching per se. Preemptive multitasking needs to deal with priorities to not waste time, and algorithms that do it

The person I am having a conversation with is advocating for threads instead of processes. How do you think threads work?

> Modern approach is to use green threads which are really cheap to switch, it is like store registers, read registers and jmp.

That’s certainly the popular approach. As I said at the beginning this approach is making a mini operating system with more bugs and less security rather than leveraging the capabilities of your operating system.

Once again, im waiting to here about your experience of maxing out processes and after that having to switch to green threads.


> The person I am having a conversation with is advocating for threads instead of processes. How do you think threads work?

I was certainly not, I explicitly said that thread-per-request is as bad as process-per-request. I could even agree that it's the worse of both worlds to some extent - none of the isolation, almost all of the overhead (except if you're using a language with a heavy runtime, like Java, where spawning a new JVM has a huge cost compared to a new thread in an existing JVM).

Modern operating systems provide many mechanisms for doing async IO specifically to prevent the need for spawning and switching between thousands of processes. Linux in particular has invested heavily in this, from select, to poll, to epoll, and now unto io_uring.

OS process schedulers are really a poor tool for doing massively parallel IO. They are a general purpose algorithm that has to keep in mind many possible types of heterogeneous processes, and has no insight into the plausible behaviors of those. For a constrained problem like parallel IO, it's a much better idea to use a purpose-built algorithm and tool. And they have simply not been optimized with this kind of scale in mind, because it's much more important and common use case to run quickly for a small number of processes than it is to scale up to thousands. There's a reason typical ulimit configurations are limited to around 1000 threads/processes per system for all common distros.


> Linux in particular has invested heavily in this, from select, to poll, to epoll, and now unto io_uring.

Correction. People who wanted to do async IO went and added additional support for it. The primary driver is node.js.

> And they have simply not been optimized with this kind of scale in mind,

yes, processes do not sacrifice security and reliability. That’s the difference.

The fallacy here is assuming that a process is just worse for hand wavy reasons and that your language feature has fa secret sauce.

If it’s not context switching then that means you have other scheduling problems because you cannot be pre-empted.

> There's a reason typical ulimit configurations are limited to around 1000 threads/processes per system

STILL waiting to hear about your experience of maxing out Linux processes on a web server - and then fixing it with green threads.

I suspect it hasn’t happened.


> The person I am having a conversation with is advocating for threads instead of processes. How do you think threads work?

Are they? I looked back and I've found this quote of them: "The overhead of process-per-request, or even thread-per-request, is absurd if you're already using a memory safe language." Doesn't seem as an advocacy for thread-per-request to me.

> As I said at the beginning this approach is making a mini operating system with more bugs and less security rather than leveraging the capabilities of your operating system.

Lets look at Apache for example. It starts a few processes and/or threads, but then each thread deals with a lot of connections. The threads Apache starts are for spreading work over several CPUs and maybe to overcome some limits of select/poll/epoll. The main approach is to track a state of a connection, and when something happens on a socket, Apache find the state of the connection and deals with events on the socket. Then it stores the new state and moves to deal with other sockets in the same manner.

It is like green threads but without green threads. Green threads streamlines all this state keeping by allowing each connection to have it's own stack. And I'd say it is easier to do right than to write a finite automata for HTTP/HTTPS.

> Once again, im waiting to here about your experience of maxing out processes and after that having to switch to green threads.

Oh, I didn't. A long long time ago I was reading stuff on networking. All of it was in one opinion: 10k kernel tasks maybe a tolerable solution, but 100k is bad. IIRC Apache had a document describing its internal architecture and explaining why it is as it is.

So I wouldn't even try to start thousands of threads. I mean I tried to start 1000s of processes when I was young and learned about fork-bombs, and this experience confirmed it for me, that 1000s of processes is not a really good idea.

Moreover I completely agree with them: if you use a memory-safe language, then it is strange to pay costs for preemptive multitasking just to have separate virtual address spaces. I mean, it will be better to get a virtual machine with JIT compiler, and run code for different connection on different instances of a virtual machine. O(1) complexity of cooperative switching will beat O(N) complexity of preemptive switching. To my mind hardware memory management is overrated.


> Lets look at Apache for example

Apache has years of engineering work - and almost weekly patches to fix issues related to security. Many of these security issues would go away if they were not using special technique to optimize performance.

But the best part of the web is its modular. So now your application doesn’t need to that. It can leverage those benefits without complexity cascade.

For example, Apache can manage more connections than your application needs running processes for.

> I was reading stuff on networking….

That’s exactly my point. Too many people are repeating advice from Google or Facebook and not actually thinking about real problems they face.

Can you serve more requests using specialized task management? Yes. You can make a mini-OS with fewer features to squeeze out more scheduling performance and that’s what some big companies did.

But you will pay for that with reduced security and reliability. To bring it back to my original complaint - you must accept that a crash can bring down multiple requests.

And it’s an insane default to design Rust around. It’s especially confusing to make all these arguments about how “unsafe” languages are, but then ignore OS safety in hopes of squeezing out a little more perf.

> So I wouldn't even try to start thousands of threads.

Please try it before arguing it doesn’t work. Fork bombing is recursive and unrelated.

> if you use a memory-safe language, then it is strange to pay costs for preemptive multitasking just to have separate virtual address spaces

Then why do these “memory-safe” languages need constant security patches? Why does chrome need to wrap each page’s JS in its own process?

In theory you’re right. If they are actually memory-safe then you don’t need to consider address spaces. But in practice the attack surface is massive and processes give you stronger invariants.


We did that at Dropbox in Python for a while. Though they switched to async after I left.

> you’re vastly over estimating the overhead of processes and number of simultaneous web connections.

It's less the actual overhead of the process but the savings you get from sharing. You can reuse database connections, have in-memory caches, in-memory rate limits and various other things. You can use shared memory which is very difficult to manage or an additional common process, but either way you are effectively back to square one with regards to shared state that can be corrupted.


You certainly can get savings. I question how often you need that.

I just said one of the costs of those saving is crashing may bring down multiple requests - and you should design with that trade off.




Consider applying for YC's Summer 2025 batch! Applications are open till May 13

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: