Prowid Photos got into a roundup on a popular blog. On Friday evening the load grew tenfold: instead of the usual 350 RPS at the peak — 3,500. The only server hit 100% CPU, pages take eight seconds to open, and then 502 errors begin. What now? There are two paths: make the server more powerful or add more servers. The choice affects not only the hosting bill but also how you must write the application. In this lesson we look at the limits of a single server, vertical and horizontal scaling, the main requirement for your code — stateless — and autoscaling.

One server and its limits

Any server runs into one of its resources: CPU, memory, disk, network or the number of database connections. A Node.js process runs JavaScript in a single thread, so one process uses one CPU core (how to use all cores is covered in the lesson "Scaling: The cluster Module and Stateless Apps").

The danger is that a server does not break gradually. A simplified queueing model says: response time ≈ processing time ÷ (1 − utilization). At 50% utilization a request takes twice as long as on an idle server, at 80% five times, at 90% ten times, at 95% twenty times. Real numbers differ, but the "hockey stick" is real — that is why servers are not loaded above 60–70%.

One server overloads, a bigger server hits a ceiling, many servers behind a balancer
One server overloads, a bigger server hits a ceiling, many servers behind a balancer

💡 Before scaling, measure and find the bottleneck (top, docker stats, metrics). It is often cheaper to add a database index or a cache than to buy a server.

Vertical and horizontal scaling

Vertical scaling (scale up) means making one server more powerful: more cores, more memory, a faster disk. It is simple and you do not have to change the code. But the method has a ceiling: the biggest machine a cloud offers is limited (hundreds of cores and terabytes of memory), and the price grows faster than the power. On top of that there is still one server — if it dies, the whole site dies — and resizing a machine usually means restarting it.

Horizontal scaling (scale out) means putting more servers side by side and spreading requests between them (the next lesson is about the balancer). There is almost no ceiling, losing one server is not a disaster, and you can grow bit by bit. The price is complexity: you need a balancer, careful deployments, monitoring, and the application must be stateless.

Vertical (scale up)Horizontal (scale out)
What we doone more powerful servermore servers
Ceilingyes: the biggest machinealmost none
A server failseverything is downthe others keep working
Application codedoes not changemust be stateless
Complexitylowhigher: balancer, deployment, state

A sensible order is: measure and optimize, then grow vertically (the simplest step), but write the code so that it can be multiplied. How many instances do you need? Take the peak, divide it by the load you can safely give to one instance (≈ 70% of its measured maximum) and add one spare — instances are needed not only for power but also to survive the failure of one of them (remember: two servers at 99% give 99.99%):