Topic Overview
Horizontal vs Vertical Scaling
Understand the difference between horizontal (scale-out) and vertical (scale-up) scaling, their trade-offs, and when to use each approach.
Scaling is the process of increasing system capacity to handle more load. Horizontal scaling adds more servers, while vertical scaling adds more resources to existing servers.
Horizontal Scaling (Scale-Out)
Horizontal scaling adds more servers to handle increased load.
How it works:
Before: 1 Server
After: Multiple Servers (2, 4, 8, ...)
Example:
1 Server → 2 Servers → 4 Servers → 8 Servers
Characteristics:
- Add more machines: Increase number of servers
- Distributed: Load distributed across servers
- Load balancing: Need load balancer
- Stateless: Servers should be stateless
Vertical Scaling (Scale-Up)
Vertical scaling adds more resources to existing server.
How it works:
Before: 2 CPU, 4GB RAM
After: 4 CPU, 8GB RAM
Example:
Small server → Medium server → Large server → XL server
Characteristics:
- Upgrade hardware: More CPU, RAM, disk
- Single server: Still one server
- No load balancer: Not needed
- Stateful OK: Can maintain state
Comparison
| Feature | Horizontal Scaling | Vertical Scaling |
|---|---|---|
| Method | Add more servers | Upgrade hardware |
| Cost | Lower (commodity hardware) | Higher (premium hardware) |
| Scalability | Nearly unlimited | Limited (hardware limits) |
| Downtime | Minimal (add servers) | Requires downtime (upgrade) |
| Fault tolerance | High (multiple servers) | Low (single point of failure) |
| Complexity | Higher (load balancing, state) | Lower (single server) |
| Use case | Web applications, microservices | Databases, stateful apps |
When to Use Each
Use Horizontal Scaling When:
- High availability needed: Multiple servers provide redundancy
- Unpredictable load: Easy to add/remove servers
- Stateless applications: Web servers, APIs
- Cost-effective: Commodity hardware cheaper
- Cloud deployment: Easy to add instances
Examples:
- Web servers
- API servers
- Microservices
- Stateless applications
Use Vertical Scaling When:
- Stateful applications: Databases, file servers
- Single-threaded apps: Can't use multiple CPUs
- Low complexity: Simpler than distributed system
- Hardware limits not reached: Can still upgrade
- Legacy systems: Hard to make distributed
Examples:
- Databases (often)
- File servers
- Single-threaded applications
- Legacy systems
Examples
Horizontal Scaling Architecture
// Load balancer distributes requests
class HorizontalScaling {
private servers: Server[];
private loadBalancer: LoadBalancer;
constructor() {
this.servers = [
new Server('server1'),
new Server('server2'),
new Server('server3')
];
this.loadBalancer = new LoadBalancer(this.servers);
}
async scaleOut(): Promise<void> {
// Add new server
const newServer = new Server(`server${this.servers.length + 1}`);
this.servers.push(newServer);
this.loadBalancer.addServer(newServer);
}
async scaleIn(): Promise<void> {
// Remove server
const server = this.servers.pop();
this.loadBalancer.removeServer(server);
}
async handleRequest(request: Request): Promise<Response> {
// Load balancer routes to server
const server = this.loadBalancer.selectServer();
return await server.handle(request);
}
}
Vertical Scaling
class VerticalScaling {
private server: Server;
constructor() {
this.server = new Server({
cpu: 2,
ram: 4, // GB
disk: 100 // GB
});
}
async scaleUp(): Promise<void> {
// Upgrade server resources
this.server.upgrade({
cpu: 4, // Double CPU
ram: 8, // Double RAM
disk: 200 // Double disk
});
// Requires downtime for upgrade
await this.server.restart();
}
}
Hybrid Approach
class HybridScaling {
// Vertical scaling for database
private database: Database; // Scale up
// Horizontal scaling for application servers
private appServers: Server[]; // Scale out
async scale(): Promise<void> {
// Scale database vertically
await this.database.scaleUp();
// Scale application servers horizontally
await this.scaleOutAppServers();
}
}
Common Pitfalls
- Only using one approach: Not considering both. Fix: Use hybrid approach when appropriate
- Horizontal scaling stateful apps: Difficult. Fix: Make stateless or use vertical scaling
- Vertical scaling too expensive: Hardware costs. Fix: Consider horizontal scaling
- Not planning for scaling: System can't scale. Fix: Design for scalability from start
Interview Questions
Beginner
Q: What is the difference between horizontal and vertical scaling?
A:
Horizontal Scaling (Scale-Out):
- Add more servers: Increase number of machines
- Distributed: Load distributed across servers
- Example: 1 server → 2 servers → 4 servers
Vertical Scaling (Scale-Up):
- Upgrade hardware: Add more resources to existing server
- Single server: Still one machine
- Example: 2 CPU → 4 CPU, 4GB RAM → 8GB RAM
Key Differences:
| Feature | Horizontal | Vertical |
|---|---|---|
| Method | Add servers | Upgrade hardware |
| Cost | Lower | Higher |
| Scalability | Unlimited | Limited |
| Fault tolerance | High | Low |
| Complexity | Higher | Lower |
When to use:
- Horizontal: Web servers, APIs, stateless apps
- Vertical: Databases, stateful apps, single-threaded
Intermediate
Q: Explain the trade-offs between horizontal and vertical scaling. When would you choose each?
A:
Horizontal Scaling Trade-offs:
Advantages:
- Nearly unlimited: Can add many servers
- High availability: Multiple servers provide redundancy
- Cost-effective: Commodity hardware cheaper
- No downtime: Add servers without downtime
- Fault tolerant: Failure of one server doesn't bring down system
Disadvantages:
- Complexity: Need load balancing, state management
- Network overhead: Communication between servers
- Stateless required: Hard to scale stateful apps
- Data consistency: Harder with distributed system
Vertical Scaling Trade-offs:
Advantages:
- Simplicity: Single server, no load balancing
- Stateful OK: Can maintain state easily
- No network overhead: All on one machine
- Lower complexity: Easier to manage
Disadvantages:
- Limited: Hardware limits (can't scale infinitely)
- Expensive: Premium hardware costs more
- Downtime: Requires downtime for upgrade
- Single point of failure: One server fails, system down
- Diminishing returns: More resources don't always help
When to choose:
- Horizontal: High availability, unpredictable load, stateless apps
- Vertical: Stateful apps, databases, simplicity needed
Senior
Q: Design a scaling strategy for a high-traffic web application that needs to handle 10 million requests per day. How do you combine horizontal and vertical scaling, handle state, and ensure high availability?
A:
class ScalableWebApplication {
private appServers: AppServer[]; // Horizontal scaling
private database: Database; // Vertical scaling (or sharding)
private cache: CacheCluster; // Horizontal scaling
private loadBalancer: LoadBalancer;
constructor() {
// Application servers: Horizontal scaling
this.appServers = [
new AppServer('app1'),
new AppServer('app2'),
new AppServer('app3')
];
// Database: Vertical scaling (or horizontal with sharding)
this.database = new Database({
cpu: 8,
ram: 32, // GB
disk: 500 // GB
});
// Cache: Horizontal scaling
this.cache = new CacheCluster([
new CacheNode('cache1'),
new CacheNode('cache2'),
new CacheNode('cache3')
]);
this.loadBalancer = new LoadBalancer(this.appServers);
}
// 1. Horizontal Scaling for App Servers
async scaleAppServers(): Promise<void> {
// Monitor load
const avgLoad = await this.getAverageLoad();
if (avgLoad > 0.8) {
// Scale out: Add servers
const newServer = await this.createAppServer();
this.appServers.push(newServer);
this.loadBalancer.addServer(newServer);
} else if (avgLoad < 0.3) {
// Scale in: Remove servers
const server = this.appServers.pop();
this.loadBalancer.removeServer(server);
await this.destroyServer(server);
}
}
// 2. Vertical Scaling for Database
async scaleDatabase(): Promise<void> {
const dbLoad = await this.database.getLoad();
if (dbLoad > 0.8) {
// Scale up: Upgrade hardware
await this.database.upgrade({
cpu: this.database.cpu * 2,
ram: this.database.ram * 2
});
}
}
// 3. Hybrid Approach
async scale(): Promise<void> {
// Auto-scale based on metrics
const metrics = await this.getMetrics();
// Scale app servers horizontally
if (metrics.appServerLoad > 0.8) {
await this.scaleOutAppServers();
}
// Scale database vertically (or horizontally with sharding)
if (metrics.databaseLoad > 0.8) {
if (this.canScaleDatabaseVertically()) {
await this.scaleUpDatabase();
} else {
// Switch to horizontal scaling (sharding)
await this.shardDatabase();
}
}
// Scale cache horizontally
if (metrics.cacheLoad > 0.8) {
await this.scaleOutCache();
}
}
// 4. Stateless Application Servers
class AppServer {
// Stateless: No local state
// State in: Database, cache, session store
async handleRequest(request: Request): Promise<Response> {
// Get session from shared store
const session = await this.sessionStore.get(request.sessionId);
// Process request
const result = await this.process(request, session);
// Save session to shared store
await this.sessionStore.set(request.sessionId, session);
return result;
}
}
// 5. Database Sharding (Horizontal for DB)
async shardDatabase(): Promise<void> {
// When vertical scaling not enough, shard
const shards = await this.createShards(4);
// Route queries to appropriate shard
this.databaseRouter = new DatabaseRouter(shards);
}
// 6. High Availability
ensureHighAvailability(): void {
// Multiple app servers (redundancy)
this.appServers = [/* multiple servers */];
// Database replication
this.database = new ReplicatedDatabase({
primary: this.primaryDB,
replicas: [this.replica1, this.replica2]
});
// Multiple load balancers
this.loadBalancers = [/* primary, secondary */];
}
}
Architecture:
Load Balancer
├─ App Server 1 (stateless)
├─ App Server 2 (stateless)
└─ App Server 3 (stateless)
↓
Database (vertical scaling or sharding)
↓
Cache Cluster (horizontal scaling)
Features:
- Horizontal scaling: App servers, cache
- Vertical scaling: Database (initially)
- Hybrid: Combine both approaches
- Stateless: App servers stateless for easy scaling
- High availability: Multiple servers, replication
Key Takeaways
- Horizontal scaling: Add more servers (scale-out), distributed, high availability
- Vertical scaling: Upgrade hardware (scale-up), single server, simpler
- Horizontal advantages: Unlimited, fault tolerant, cost-effective
- Vertical advantages: Simpler, stateful OK, no network overhead
- Hybrid approach: Use both (horizontal for apps, vertical for database)
- Stateless: Make app servers stateless for easy horizontal scaling
- Best practices: Design for scalability, use horizontal when possible, combine both approaches