Day 2 我們了解了一個 Request 從 Browser、DNS、Server 到 Database 的基本旅程。
最簡單的架構可能是:
Users
↓
Server
↓
Database
但當產品從 100 個使用者成長到 10,000、甚至 1,000,000 個使用者,一台 Server 可能逐漸處理不完所有 Request。
這時候就會遇到 System Design 裡非常重要的問題:
Server 不夠用了,我們該怎麼擴充系統?
最基本的兩種方法就是:
Vertical Scaling
vs
Horizontal Scaling
假設一開始 Server 每秒只需要處理:
100 requests / second
後來產品流量增加:
100 requests/sec
↓
1,000 requests/sec
↓
10,000 requests/sec
Server 的 CPU、Memory、Network 等資源開始接近極限,可能出現:
這時候我們就需要增加系統可以處理的 Capacity。
這就是 Scaling。
Scalability(可擴展性)可以簡單理解成:
當 workload 增加時,系統能否透過增加資源來處理更多需求。
最基本有兩種方式:
Vertical Scaling → Scale Up
Horizontal Scaling → Scale Out
假設原本 Server 是:
CPU: 2 cores
RAM: 4 GB
效能不夠後升級成:
CPU: 16 cores
RAM: 64 GB
Architecture 幾乎沒有改變:
Before
Users
↓
Small Server
After
Users
↓
Bigger Server
這就是:
Vertical Scaling(垂直擴展 / Scale Up)
核心概念就是:
不增加 Server 數量,而是讓原本的 Server 變得更強。
最大的優點就是:
簡單。
通常不需要因為 Scaling 就重新設計整個 Application Architecture。
優點包含:
例如 Side Project 原本使用:
1 CPU
2 GB RAM
使用者增加後升級成:
4 CPU
8 GB RAM
可能就已經足夠。
沒有必要一開始就建立非常複雜的 Distributed System。
最大的限制是:
一台機器不可能無限升級。
例如:
2 cores
↓
8 cores
↓
32 cores
↓
64 cores
↓
???
Hardware 一定存在上限。
而且越高階的機器,成本通常也會越高。
即使今天買了一台非常強的 Server:
Users
↓
Powerful Server
它還是只有:
1 Server
如果這台 Server 掛掉:
Users
↓
Server ❌
整個服務可能就跟著無法使用。
這就是:
Single Point of Failure(SPOF)
也就是系統中某個 Component 一旦故障,就可能讓整個服務無法正常運作。
第二種方法不是一直把同一台 Server 變強。
而是:
增加更多 Server。
例如原本:
Users
↓
Server #1
變成:
┌── Server #1
Users ────────┼── Server #2
├── Server #3
└── Server #4
這就是:
Horizontal Scaling(水平擴展 / Scale Out)
核心概念:
1 Server
↓
2 Servers
↓
4 Servers
↓
10 Servers
透過增加機器數量,讓整個系統有能力處理更多 Request。
Vertical Scaling
↓
Scale Up
↓
一台機器變強
Horizontal Scaling
↓
Scale Out
↓
增加更多機器
用圖來看:
Vertical Scaling
Server
↓
Bigger Server
Horizontal Scaling
Server
↓
┌──────┼──────┐
↓ ↓ ↓
Server Server Server
#1 #2 #3
假設一台 Server 可以處理一定數量的 Request。
Traffic 增加後,我們可以加入更多 Server:
Server #1
Server #2
Server #3
Traffic 再增加:
3 Servers
↓
5 Servers
↓
10 Servers
因此 Horizontal Scaling 的核心優勢是:
可以透過增加更多節點,提高整個系統的 Capacity。
當然,實際情況不會永遠線性成長。
Database、Network、Shared Resources 都可能成為新的 Bottleneck。
但核心概念是:
我們不再依賴單一機器提供所有運算能力。
如果只有:
User
↓
Server #1
Server #1 掛掉,服務可能直接中斷。
但如果有:
Server #1 ✅
Server #2 ❌
Server #3 ✅
即使其中一台 Server 故障,其他健康的 Server 還有機會繼續處理 Request。
所以 Horizontal Scaling 除了 Scalability,也可以成為提升 Availability 與 Fault Tolerance 的基礎。
但是新的問題馬上出現了。
現在我們有:
Server #1
Server #2
Server #3
Server #4
大量 Request 進來:
Request #1
Request #2
Request #3
Request #4
...
到底要怎麼分配?
我們需要一個 Component 放在 Client 和 Servers 中間:
┌── Server #1
│
Users → ??? ───────┼── Server #2
│
└── Server #3
它負責接收 Request,再分配給不同 Server。
這個 Component 就是:
Load Balancer
Architecture 變成:
┌── Server #1
│
Users → Load Balancer├── Server #2
│
└── Server #3
所以我們不是因為「System Design 都要放 Load Balancer」才加入它。
而是:
Traffic 增加
↓
一台 Server 不夠
↓
Horizontal Scaling
↓
增加多台 Server
↓
Request 要怎麼分配?
↓
Load Balancer
這就是:
Problem → Solution
Horizontal Scaling 看起來很強,但增加更多 Server,也代表系統開始變得更複雜。
原本:
User → Server → Database
現在:
┌── Server #1
│
User → Load Balancer ├── Server #2
│
└── Server #3
↓
Database
我們開始需要考慮:
所以:
Scalability 增加的同時,System Complexity 通常也會增加。
這就是 Trade-off。
Horizontal Scaling 還會帶出另一個重要概念:
Stateless Server
假設 User 登入後,Session 只存在 Server #1:
User
↓
Server #1
Session:
Alvin = logged in
下一個 Request 卻被分配到:
Server #2
Server #2 並沒有 Server #1 本機的 Session。
這就是 Stateful Server 在 Horizontal Scaling 時可能遇到的問題之一。
因此很多 Web Backend 會盡量設計成 Stateless。
簡單來說:
Server 不依賴自己本機保存的 Client Session State。
共享的 State 可以放到其他地方,例如:
Database
Redis
External Session Store
讓不同 Server 都能取得需要的資料:
┌── Server #1 ──┐
│ │
User → Load Balancer── Server #2 ──┼── Shared Store
│ │
└── Server #3 ──┘
這樣 Request 被分配到不同 Server 時,就更容易進行 Horizontal Scaling。
| Vertical Scaling | Horizontal Scaling | |
|---|---|---|
| 又稱 | Scale Up | Scale Out |
| 方法 | 升級單一機器 | 增加更多機器 |
| Example | 增加 CPU / RAM | 增加 Server |
| Architecture | 相對簡單 | 相對複雜 |
| Hardware Limit | 有明顯上限 | 可增加節點,但仍受其他 Bottleneck 限制 |
| SPOF | 單機架構容易存在 | 可降低對單一 Server 的依賴 |
| Complexity | 較低 | 較高 |
| 常見問題 | Hardware Limit | Load Balancing、State、Consistency |
但這不代表:
Horizontal Scaling > Vertical Scaling
真正的答案仍然是:
Depends on the Requirements.
不一定。
假設今天只有:
100 users
一台普通 Server 就可以輕鬆處理所有 Traffic。
這時候直接建立:
Load Balancer
5 Backend Servers
Redis
Kafka
Kubernetes
可能完全沒有必要。
反而會增加:
所以我們又回到 Day 1 的核心:
System Design is about trade-offs.
好的 System Design 並不是使用最多技術。
而是:
使用足夠解決目前問題的 Architecture,同時保留未來擴展的可能性。
假設原本的 Bottleneck 是 Backend:
Users
↓
Backend ← Bottleneck
↓
Database
所以我們增加很多 Backend Servers:
┌── Server #1
├── Server #2
Users ────────┼── Server #3
├── Server #4
└── Server #5
↓
Database
Backend 的問題可能改善了。
但是所有 Server 都開始大量 Query 同一個 Database。
新的 Bottleneck 可能變成:
Database ← New Bottleneck
所以 System Design 並不是:
解決問題 → Done
而比較像:
找到 Bottleneck
↓
解決 Bottleneck
↓
Traffic 增加
↓
找到新的 Bottleneck
↓
再次調整 Architecture
這也是為什麼之後我們還需要學:
每一個 Component 都是在不同情況下解決不同的問題。
Day 3 最重要的是建立兩種 Scaling 的基本概念。
Scale Up
↓
把同一台 Server 變強
↓
More CPU
More RAM
More Resources
優點:
缺點:
Scale Out
↓
增加更多 Server
↓
Server #1
Server #2
Server #3
...
優點:
缺點:
如果用一張圖總結:
Vertical Scaling
Server
↓
Bigger Server
Horizontal Scaling
Server
↓
┌────────┬────────┐
↓ ↓ ↓
Server Server Server
#1 #2 #3
今天最重要的一句話:
Vertical Scaling 是把一台機器變強;Horizontal Scaling 是增加更多機器。兩者都能增加 Capacity,但會帶來不同的 Trade-off。
現在我們決定使用 Horizontal Scaling:
Server #1
Server #2
Server #3
但是新的問題非常明顯:
大量 Request 進來時,到底要送去哪一台 Server?
所以 Day 4,我們會正式加入第一個重要的 System Design Component:
Load Balancer
下一篇:
Day 4|Load Balancer 是什麼?多台 Server 到底要怎麼分配 Request?
我們會開始了解:
並且把目前的 Architecture:
User → Server → Database
進化成:
┌── Server #1
│
User → Load Balancer ├── Server #2
│
└── Server #3
↓
Database
我們的 System Design Architecture,也會從 Day 4 開始慢慢變得更接近真實世界。