4 ms·
I see this argument all the time but its not the fork() that is the most expensive anymore, its the actual program initialization after the fork(). If your app
by NathanKP 8y ago
I see this argument all the time but its not the fork() that is the most expensive anymore, its the actual program initialization after the fork(). If your app is non trivial (lets say a websocket based chat server that needs to persist messages to a DB and use pubsub to sync them to other processes) it probably needs a connection to a database, a connection to a cache server like Redis or Memcached, etc, or perhaps a connection to some other backend service. Reinitializing these dependency connections from scratch in a new forked process for every single incoming websocket connection is expensive and slow.
On the other hand a Node.js or Go program can have a preestablished pool of keep alive connections to the backends already ready to go and reuse that connection pool for many hundreds or even thousands of concurrent websocket connections. You can approximate something like this with the fork() model by having a local daemon process that manages the connection pool and have your forked process talk to that local helper daemon when it needs a connection, but you are still going to pay a penalty for that compared with having a fully preestablished connection ready to use right there in the process already
- zorga 8y ago> If your app is non trivial (lets say a websocket based chat server that needs to persist messages to a DB and use pubsub to sync them to other processes) it probably needs a connection to a database, a connection to a cache server like Redis or Memcached, etc All things that are already generally connection pooled so this point is moot. > On the other hand a Node.js or Go program can have a preestablished pool of keep alive connections to the backends already ready to go Which has nothing remotely to do with why they scale. Also so can the forking process, it can quite easily even have a pool of preforked workers ready to go and handle requests to avoid the cost of the fork. None of the things you've said have anything to do with why Node and Go are more scalable than a forking server. The issue is ram, not the price of setting up connections; processes are much heavier on ram and limit your number of concurrent clients, Node and Go are event driven single process apps that scale better because they consume less resources, not because of all that other stuff you said. I don't think you really understand what you're saying or you're comparing apples and oranges and don't know it.
- geocar 8y agoThen consider posix_spawn(), since it pays that cost, but then we have to pay IPC as well: fasthttp(go) can do around 80k/sec on my laptop; dash(C) can do almost 88k/sec on my laptop†. As soon as dash does IPC, it drops to around 51k/sec, and as soon as it needs a reply, we're down to 25k/sec††. I see no reason to believe fasthttp would do any faster. That means I'm spending around 70% of my time in IPC -- something posix_spawn() would let me avoid (if my application were designed to do so). My same laptop will do 100k/sec posix_spawn() so I'd find this difficult to believe (1-4 msec per call) fork() or exec() is the bottleneck for any application with this architecture. Do you think posix_spawn() represents 70% of your costs? If our goal is to beat 51k/sec requests, sure, but NodeJS on my laptop (btw) gets 10k/sec, so if it's a contender, I'd say posix_spawn() is as well. † https://github.com/geocar/dash/blob/master/README.techempower.md https://github.com/geocar/dash/blob/master/README.techempowe... †† https://github.com/geocar/dash/blob/master/README.md https://github.com/geocar/dash/blob/master/README.md
- marcosdumay 8y agoWell, you can manage resources by shared memory and semaphores. That will make nearly all of the environment setting time go away. Better yet if you just serialize the processes and assign resources to a serial number. What is just another way to make a NxM server, so maybe forget about it...
- romeisendcoming 8y agoYou can prefork. That is a tried and true method. And why do you need to create so many connections? Certainly you can architect the solution better than that.