Back-end · Senior

Scalability: vertical, horizontal and load balancing

Scaling means making a system handle more load without falling over. As a senior dev, you need not only to know the strategies, but to explain their trade-offs and identify the real bottleneck — which is almost never the application. This is one of the core topics in system design interviews.

Vertical vs horizontal

There are two ways to scale. Vertical (scale up) means getting a bigger machine: more CPU, more RAM. Horizontal (scale out) means adding more machines, splitting the load among them. The analogy: scaling vertically is swapping your car for a truck; scaling horizontally is buying several cars. Each solves a different kind of problem.

AspectVertical (scale up)Horizontal (scale out)
HowMore powerful machineMore machines
LimitPhysical hardware ceilingPractically unlimited
ComplexityLow (no code changes)Higher (needs coordination)
ResilienceSingle point of failureOne machine goes down, the others keep going

Why stateless is the key

Scaling horizontally only works well if the services are stateless: no request depends on which machine handled the previous one. If the server keeps state in memory (a session, for example), a user "stuck" on that machine can't be served by another. That's why state moves out — to a database, a shared cache like Redis. With stateless services, adding machines is trivial.

Load balancer

With multiple instances, someone has to distribute the requests among them: the load balancer. It sits in front, receives all the traffic and splits it up:

             +----------------+
   clients   |  Load Balancer |
  ---------> |  (round-robin) |
             +----------------+
               /     |      \
              v      v       v
          [App 1] [App 2] [App 3]   <- stateless instances
              \      |      /
               v     v     v
            +-------------------+
            |     Database      |   <- shared state
            +-------------------+

The simplest strategy is round-robin: requests are distributed in rotation, one to each instance in sequence. Other options take into account which instance is least busy (least connections) or the user's location.

The database as a bottleneck

Here's the point that separates juniors from seniors: you can have 50 instances of the application, but if they all hit the same database, the database becomes the bottleneck. The application scales easily; state doesn't. The main ways out:

  • Read replicas: copies of the database that serve reads only, relieving the primary (which keeps the writes). Works well when there are far more reads than writes.
  • Sharding: partitioning the data across several databases (e.g. users A-M in one, N-Z in another), which also spreads the writes — but with a big increase in complexity.
Scaling the application is the easy part; scaling the state is the hard part. When someone says "just spin up more servers", ask: can the database handle it?

Trade-offs

There's no free lunch. Horizontal scaling brings resilience and nearly unlimited scale, but requires stateless services, load balancers and deals with the complexity of distributed systems — including consistency decisions that show up in the CAP theorem. Vertical is simple but has a ceiling and is a single point of failure. In practice, mature systems combine both: they scale vertically up to a point and horizontally from there.

Conclusion

Scalability is about removing bottlenecks, not blindly adding machines. Keep services stateless, use a load balancer to distribute load and, above all, remember that the database is usually the real limit. Knowing where the bottleneck is and which trade-off to accept is exactly the kind of reasoning expected of a senior.

Read also

Back to track