System Design Patterns
Essential system design patterns:
Load Balancing Strategies
Round Robin: Request 1 → Server A, Request 2 → Server B, Request 3 → Server C
Least Connections: Route to server with fewest active connections
Weighted: Assign different weights based on server capacity
IP Hash: Route based on client IP hash for session affinity
Caching Patterns
// Cache-Aside Pattern
const getUser = async (userId) => {
// Try cache first
let user = await cache.get(`user:${userId}`);
if (!user) {
// Cache miss - fetch from database
user = await database.getUser(userId);
await cache.set(`user:${userId}`, user, 3600); // 1 hour TTL
}
return user;
};
// Write-Through Pattern
const updateUser = async (userId, userData) => {
// Update database first
const user = await database.updateUser(userId, userData);
// Then update cache
await cache.set(`user:${userId}`, user, 3600);
return user;
};
Database Patterns
Master-Slave Replication:
- Master handles writes
- Slaves handle reads
- Eventual consistency
Database Sharding:
- Horizontal partitioning
- Shard by user ID, geography, or feature
- Each shard is independent
CQRS (Command Query Responsibility Segregation):
- Separate read and write models
- Optimize each for its specific use case
Microservices Communication
Synchronous:
- HTTP/REST APIs
- GraphQL
- gRPC
Asynchronous:
- Message queues (RabbitMQ, SQS)
- Event streaming (Kafka)
- Pub/Sub patterns
Scalability Patterns
- Horizontal Scaling: Add more servers
- Vertical Scaling: Upgrade server hardware
- Auto Scaling: Dynamic scaling based on metrics
- Circuit Breaker: Prevent cascade failures
- Bulkhead: Isolate critical resources