Scaling: Vertical vs Horizontal¶
Vertical scaling (scale up): Add more resources to the existing server: more CPU cores, more RAM, faster SSD, more network bandwidth. Simple — no code changes required. No distribution complexity.
Why it fails: hardware has physical limits. A single machine can have at most ~hundreds of CPU cores and ~tens of TB of RAM. Beyond that, adding more hardware has diminishing returns (NUMA effects, interconnect bottlenecks). Also: no fault tolerance — one server is a single point of failure.
When to use: early stage systems where vertical scaling buys time before the complexity of horizontal scaling is warranted. Database primaries often scale vertically (adding more RAM for buffer cache is simpler than sharding).
Horizontal scaling (scale out): Add more machines. Distribute the load across many nodes. In theory, scales linearly: 2× machines = 2× capacity.
Why it is hard: services must be stateless (no session data in memory). Shared state must be externalized to a distributed store (Redis, DB). Data must be partitioned (sharding). Distributed coordination introduces consistency challenges (see CAP). Network calls between services add latency and failure modes.
Real-world usage: Proxel's web scraping workers are stateless — any worker can pick up any job from the Redis Stream. Scaling from 3 to 20 workers was a config change. The Redis Stream (stateful component) scales by increasing Redis memory or switching to Redis Cluster.
Common pitfall¶
Assuming a service is stateless just because it's stateless most of the time is a common source of horizontal-scaling bugs — an in-memory rate limiter, an in-process cache, or a WebSocket connection tracked in a local variable all quietly reintroduce per-instance state. The symptom is specific: behavior that's correct with 1 replica and inconsistent with N (a rate limit that's effectively N times looser than configured, because each instance counts independently). Anything truly shared has to live in an externalized store (Redis, a database), not in the process's own memory, for horizontal scaling to actually behave as advertised.