Expert · Deployment and scaling · topic 50 of 54 · 30 min
Scaling: handling more users
Explanation
Two ways to grow
Vertical scaling means a bigger machine: more CPU, more RAM. It is simple, because the code does not change, but there is a top limit and one machine is still one point of failure. Horizontal scaling means more machines running the same app, with traffic shared between them. It can grow much further and survives one machine dying, but it needs some design work.
| Vertical (bigger server) | Horizontal (more servers) | |
|---|---|---|
| How | Upgrade CPU and RAM | Add copies behind a load balancer |
| Code changes | None | Servers must be stateless |
| Limit | The biggest machine you can rent | Very high |
| If one machine fails | The app is down | Others keep serving |
Stateless servers
A server is stateless when it keeps nothing important in its own memory between requests. If user sessions or uploaded files live in one server's memory or disk, the next request may go to a different server that knows nothing about them. So move state out: sessions to Redis, files to object storage (like Amazon S3), data to the database. Then any server can answer any request.
import { createClient } from 'redis';
const redis = createClient({ url: process.env.REDIS_URL });
await redis.connect();
async function saveSession(sessionId, data) {
// expires after 24 hours
await redis.set('session:' + sessionId, JSON.stringify(data), { EX: 60 * 60 * 24 });
}
async function loadSession(sessionId) {
const raw = await redis.get('session:' + sessionId);
return raw ? JSON.parse(raw) : null;
}Load balancers and health checks
A load balancer sits in front of your servers and passes each request to one of them. Round robin sends requests to each server in turn: A, B, C, A, B, C. Least connections sends each request to the server that is busy with the fewest requests right now, which is better when some requests are slow. Examples are nginx, HAProxy and the managed load balancers of every cloud.
upstream notes_api {
least_conn;
server 10.0.0.11:3000;
server 10.0.0.12:3000;
server 10.0.0.13:3000;
}
server {
listen 80;
location / { proxy_pass http://notes_api; }
}A health check is a small endpoint, like GET /healthz, that the load balancer calls every few seconds. If a server stops answering 200, the load balancer stops sending it traffic until it recovers. Keep the check cheap, but make it test what matters, for example that the database answers SELECT 1.
Scaling the database
Most apps read far more than they write: people view products many times for each order. A read replica is a copy of the database that receives every change from the main (primary) database and answers read queries. Writes go to the primary; reads can go to replicas. The copy is not instant: the small delay is called replication lag.
Sharding splits one big table across several databases, for example users with ids 1 to 1 crore in shard 1 and the next crore in shard 2. Each shard holds part of the data, so writes spread out too. It is powerful but complex: queries across shards and moving data between them are hard. Most apps never need it; try indexes, caching and replicas first.
CDNs and autoscaling
A CDN (Content Delivery Network) keeps copies of static files, like images, CSS, JavaScript and videos, on servers in many cities. A user in Guwahati gets the image from a nearby CDN server instead of your server in Mumbai: faster for them, less load for you. Autoscaling adds servers automatically when CPU or request count goes up, and removes them when traffic falls, so you pay for busy hours only.
Watch the lesson
Scaling: handling more users · 1/6
Scaling means serving more users without slowing down. There are two ways: a bigger server, or more servers.
Prefer a video by a teacher? Find free videos on “horizontal vs vertical scaling load balancer explained” on YouTube ↗
In real life: Board exam results day
On results day, a state board website gets lakhs of students in the first ten minutes, compared with a few hundred on a normal day. A well-prepared team runs the results API on many stateless servers behind a load balancer with health checks, and autoscaling adds more as traffic rises. Results are read-only, so they are served from read replicas and cached in Redis by roll number. The logo, CSS and PDF mark sheets come from a CDN. The primary database barely notices, and students get their results in seconds instead of a spinning wheel.
Practice (0/3 done)
Write leastConnections(servers) where servers is a list of { name, active, healthy }. Return the name of the healthy server with the fewest active connections. If two are tied, return the first one in the list. If no server is healthy, return null.
Write createRoundRobin(servers) that returns an object with a next() method. servers is a list of { name, healthy }. Each call to next() returns the name of the next server in turn (A, B, C, A, ...), skipping servers whose healthy is false at that moment. Health can change between calls. If no server is healthy, next() returns null.
A college results site normally has 200 visitors an hour, but on results day expects 2 lakh visitors in the first hour. Write a one-page scaling plan.
Quick quiz
Read more (free)
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.