📈 Level 2 — Scalability
Learn how to design systems that grow from 100 users to 100 million.
2.1 Vertical vs Horizontal Scaling
Visual Comparison
| Vertical | Horizontal | |
|---|---|---|
| Cost | Expensive hardware | Commodity servers |
| Limit | Hardware ceiling | Nearly unlimited |
| Fault Tolerance | Single point of failure | Redundant |
| Complexity | Simple | Requires coordination |
💻 JS Example: Horizontal Scaling with Node.js Cluster
In Node.js, you can scale horizontally across multiple CPU cores on a single machine using the cluster module.
javascript
const cluster = require("cluster");
const http = require("http");
const numCPUs = require("os").cpus().length;
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);
// Fork workers for each CPU core
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on("exit", (worker) => {
console.log(`worker ${worker.process.pid} died. Respawning...`);
cluster.fork();
});
} else {
// Workers can share any TCP connection
http
.createServer((req, res) => {
res.writeHead(200);
res.end("Hello from scaled server!\n");
})
.listen(8000);
}2.2 CAP Theorem
A distributed system can only guarantee 2 out of 3 properties simultaneously.
| System Type | Guarantees | Example Scenario |
|---|---|---|
| CP | Correct data, may be unavailable | Banking: Reject transaction if network split to avoid double spending. |
| AP | Always responds, may return stale data | Social Media: Show old feed rather than an error page. |
| CA | Consistent + Available | Local DB: High reliability on a single machine, but fails on network split. |
2.3 Consistency Models
Eventual vs Strong Consistency
💻 JS Example: Handling Eventual Consistency
When dealing with eventual consistency, clients often need to retry or "poll" for the latest state.
javascript
async function getConsistentData(id, expectedValue, retries = 3) {
for (let i = 0; i < retries; i++) {
const data = await fetch(`/api/data/${id}`).then((r) => r.json());
if (data.value === expectedValue) return data;
console.log(`Stale data detected, retry ${i + 1}...`);
await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1s
}
throw new Error("Failed to reach consistency");
}2.4 How to Scale: Step by Step
The 5-Stage Journey
2.5 Rate Limiting
Protects your system from being overwhelmed by too many requests.
💻 JS Example: Basic Token Bucket Implementation
A conceptual look at how a rate limiter might track requests in memory.
javascript
class RateLimiter {
constructor(limit, windowMs) {
this.limit = limit;
this.requests = new Map(); // Store counts per IP
}
isAllowed(ip) {
const now = Date.now();
const count = this.requests.get(ip) || 0;
if (count >= this.limit) {
return false; // Rate limit exceeded
}
this.requests.set(ip, count + 1);
// Reset limit after window expires
setTimeout(() => this.requests.delete(ip), 60000);
return true;
}
}✅ Checklist Before Moving On
- [ ] I can explain CAP theorem with a real-world example
- [ ] I know when to scale vertically vs horizontally
- [ ] I understand eventual vs strong consistency
- [ ] I can draw the 5-stage scaling journey
➡️ Next: Level 3 — Databases
