Chapter 4: Single Server Architecture — Where Everything Starts
Every system starts on a single server. Understanding this baseline helps you recognize when and why you need to scale beyond it.
The Simplest Architecture
User (browser) ──HTTP──► Single Server
├── Web Server (nginx)
├── Application (your code)
├── Database (PostgreSQL)
└── File storage (local disk)
Everything on ONE machine.
Simple. Works for thousands of users.
What One Server Can Handle
A modern server (32 cores, 128GB RAM, NVMe SSD) can handle more than most people think:
- ~50,000 concurrent HTTP connections
- ~5,000-10,000 database queries/second
- ~1,000-5,000 complex API requests/second
- Millions of rows in PostgreSQL (with proper indexes)
💡 Don't Scale Prematurely
A single well-optimized server handles more traffic than most startups will ever see. Instagram had 25 million users on a handful of servers. Don't add complexity until you need it.
When Single Server Breaks
| Problem | Symptom | Solution (next chapters) |
|---|---|---|
| CPU saturated | Slow responses, high load average | Horizontal scaling (more servers) |
| RAM exhausted | Swapping, OOM kills | Vertical scaling or separate DB server |
| Disk full | Write failures | Object storage, archiving |
| Single point of failure | Server dies = total outage | Redundancy, failover |
| Database bottleneck | Slow queries under load | Read replicas, caching |
| Geographic latency | Slow for distant users | CDN, multi-region |
First Evolution: Separate Database
Step 1: Move database to its own server
User ──► App Server (stateless logic)
│
▼
DB Server (PostgreSQL)
Why: App and DB compete for RAM/CPU on same machine.
Separating lets each be optimized independently.
App server can now be replicated (stateless).
Second Evolution: Add a Load Balancer
Step 2: Multiple app servers behind a load balancer
User ──► Load Balancer ──► App Server 1
──► App Server 2
──► App Server 3
│
▼
DB Server
Why: Horizontal scaling. Handle more requests.
If one app server dies, others continue.
App servers must be STATELESS (no local session data).
Third Evolution: Add Caching
Step 3: Cache hot data in Redis
User ──► LB ──► App Servers ──► Redis (cache)
│ │ miss
│ ▼
└──────────► PostgreSQL
Why: Most reads hit the same data (hot data).
Redis serves 100K+ ops/sec from RAM.
Reduces DB load by 90%+.
The Evolution Path
Single Server
│
▼ (DB bottleneck)
Separate DB Server
│
▼ (need more compute)
Multiple App Servers + Load Balancer
│
▼ (DB reads too slow)
Add Cache (Redis)
│
▼ (DB writes bottleneck)
Read Replicas
│
▼ (data too large for one DB)
Database Sharding
│
▼ (global users, latency)
Multi-Region / CDN
│
▼ (complex async workflows)
Message Queues
│
▼ (microservices)
Service-Oriented Architecture
⚠️ Key Principle: Stateless Servers
For horizontal scaling to work, app servers must be stateless — no user sessions, no local files, no in-memory state that can't be lost. All state goes to external stores (database, Redis, object storage). Any request can go to any server.
Key Takeaways
- Start with one server — it handles more than you think
- First split: separate app server from database server
- Second split: multiple stateless app servers + load balancer
- Add cache (Redis) to reduce database load
- Stateless servers are the foundation of horizontal scaling
- Scale only when you have measured evidence of bottlenecks