測驗:系統擴展與負載均衡
共 5 題,點選答案後會立即顯示結果
1. Vertical Scaling(垂直擴展)的做法是什麼?
2. 水平擴展(Horizontal Scaling)相較於垂直擴展,最大的優勢是什麼?
3. Load Balancer 使用 Round Robin 演算法時,請求是如何分配的?
4. 水平擴展後,如果使用者登入狀態(Session)存在伺服器記憶體裡,會發生什麼問題?
5. 以下 Nginx 設定片段的作用是什麼?
**系列**:系統設計 30 概念(第 3 篇,共 6 篇)
**難度**:L2-進階
**前置知識**:#01 網路基礎(Client-Server 架構)、#02 API 設計(理解請求如何進入系統)
**涵蓋概念**:#12 Vertical Scaling、#13 Horizontal Scaling、#14 Load Balancers
一句話說明
當一台伺服器撐不住流量時,你有兩條路:把這台機器變強(垂直擴展),或是多叫幾台來幫忙(水平擴展)。多台機器之間需要有人分配工作,那就是 Load Balancer。
為什麼你需要知道這些?
你用 AI 幫你寫了一個 Web 應用,部署到一台雲端伺服器上,跑得好好的。然後有一天流量暴增 —— 你的應用開始變慢、回應超時、甚至直接掛掉。
這時候你在架構文件、雲端服務的設定頁面、或是 AI 給你的部署建議中,會一直看到這些詞:
- 「建議做 horizontal scaling」
- 「先 scale up 到更大的 instance」
- 「前面加一個 load balancer」
看不懂這些,就無法做出正確的擴展決策。這篇教你讀懂它們。
概念 #12:Vertical Scaling(垂直擴展)
一句話翻譯
把現有的那台伺服器升級,讓它更強。 就像把你的筆電從 8GB RAM 升到 32GB RAM。
最小範例:雲端設定你會看到什麼
在 AWS、GCP 這類雲端平台,垂直擴展就是換一個更大的 instance type:
# AWS EC2 垂直擴展示意
目前:t3.small → 2 vCPU, 2 GB RAM
升級:t3.xlarge → 4 vCPU, 16 GB RAM
升級:m5.4xlarge → 16 vCPU, 64 GB RAM
Code language: CSS (css)翻譯:不改架構、不改程式碼,只是把機器從「小台」換成「大台」。
架構長這樣
升級前:
Client → [小伺服器 2 CPU / 2GB RAM]
升級後:
Client → [大伺服器 16 CPU / 64GB RAM]
架構完全沒變,只是機器變強了。
Code language: CSS (css)優缺點速查
| 面向 | 說明 |
|---|---|
| 優點 | 架構最簡單,不需改程式,不需處理多機器同步問題 |
| 缺點 | 有天花板(一台機器的硬體有上限),而且只有一台 —— 它掛了就全掛了 |
| 適合 | 專案初期、流量穩定可預測、資料庫這類不容易拆分的元件 |
你會在哪裡遇到
- 雲端控制台的「Change Instance Type」按鈕
- AI 建議你「upgrade your database server」
- Docker Compose 設定裡調整
mem_limit和cpus
# docker-compose.yml 裡限制資源的設定
services:
web:
image: my-app
deploy:
resources:
limits:
cpus: '4.0' # 限制最多用 4 顆 CPU
memory: 8G # 限制最多用 8GB 記憶體
Code language: PHP (php)翻譯:這段不是在寫程式,只是在告訴 Docker「這個容器最多可以用多少資源」。調高這些數字就是一種垂直擴展。
概念 #13:Horizontal Scaling(水平擴展)
一句話翻譯
多開幾台一樣的伺服器,把工作分給它們。 就像餐廳忙不過來時,不是讓一個廚師更努力,而是多請幾個廚師。
架構長這樣
擴展前(1 台伺服器):
Client → [Server]
水平擴展後(3 台伺服器):
Client → [Load Balancer] → [Server 1]
→ [Server 2]
→ [Server 3]
Code language: CSS (css)注意中間多了一個 Load Balancer(下一節會講),因為你現在有多台伺服器,需要有人來決定「這個請求要送去哪一台」。
最小範例:Kubernetes 你會看到什麼
# Kubernetes Deployment — 水平擴展的設定
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3 # ← 開 3 份一模一樣的伺服器
selector:
matchLabels:
app: my-app
template:
spec:
containers:
- name: my-app
image: my-app:latest
Code language: PHP (php)翻譯:replicas: 3 就是水平擴展的核心 —— 告訴 Kubernetes「跑 3 份一模一樣的我的應用」。想要更多?把 3 改成 10 就好了。
自動擴展:HPA
在 Kubernetes 裡,你還會看到 HPA(Horizontal Pod Autoscaler),它會自動幫你決定要開幾台:
# HPA — 自動水平擴展
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
spec:
minReplicas: 2 # 最少 2 台
maxReplicas: 10 # 最多 10 台
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # CPU 使用率超過 70% 就加機器
Code language: PHP (php)翻譯:「平常至少跑 2 台,最多可以開到 10 台。當 CPU 使用率超過 70%,就自動多開一台。」—— 這就是自動化的水平擴展。
優缺點速查
| 面向 | 說明 |
|---|---|
| 優點 | 理論上無上限(機器可以一直加)、有冗餘(一台掛了還有其他台頂著) |
| 缺點 | 架構變複雜了,要處理「多台機器之間的資料一致性」問題 |
| 適合 | 流量大且不可預測、需要高可用性(不能停機)的系統 |
水平擴展帶來的新問題
多台伺服器看起來很美好,但它帶來一個關鍵問題 —— 狀態(State)放在哪裡?
問題場景:
User 登入 → 請求送到 Server 1 → Server 1 記住「User 已登入」
User 下一個請求 → 被送到 Server 2 → Server 2 不知道 User 已登入!
解法:
1. Session 存在獨立的地方(如 Redis),所有 Server 都去那邊查
2. 使用 IP Hash 讓同一個 User 永遠送到同一台(下一節會講)
3. 使用 Stateless 設計(用 JWT Token,每次請求都帶著身份資訊)
翻譯:水平擴展要求你的應用盡量是「無狀態」的 —— 不要把資料存在單一伺服器的記憶體裡。看到 AI 把 session 改用 Redis 存,或是改用 JWT,通常就是在解決這個問題。
概念 #14:Load Balancers(負載均衡器)
一句話翻譯
水平擴展後的「交通指揮官」,決定每個請求要送去哪台伺服器。
架構長這樣
┌→ [Server 1] 處理 33% 的請求
[Client] → [LB] ───┼→ [Server 2] 處理 33% 的請求
└→ [Server 3] 處理 33% 的請求
Code language: CSS (css)Load Balancer(簡稱 LB)坐在 Client 和 Server 群之間。還記得上一篇提到的 Reverse Proxy 嗎?Load Balancer 本質上就是 Reverse Proxy 的一種應用 —— 它代理了後端的多台伺服器,Client 不需要知道後面有幾台、分別是什麼 IP。
三種常見的分配演算法
Load Balancer 怎麼決定把請求送給誰?以下是三種最常見的演算法:
1. Round Robin(輪流分配)
請求 1 → Server 1
請求 2 → Server 2
請求 3 → Server 3
請求 4 → Server 1 ← 回到第一台,繼續輪流
請求 5 → Server 2
請求 6 → Server 3
翻譯:像發撲克牌一樣,一人一張輪流發。最簡單、最常見。
適合:每個請求的處理時間差不多的場景。
不適合:有些請求很重(要 10 秒),有些很輕(0.1 秒),輪流發會讓某台伺服器堆積過多重請求。
2. Least Connections(最少連線數)
目前狀態:
Server 1:5 個連線
Server 2:2 個連線 ← 最少
Server 3:8 個連線
新請求 → 送給 Server 2(因為它目前最閒)
翻譯:看誰手上工作最少,就把新任務給誰。比 Round Robin 更聰明。
適合:請求處理時間不均勻的場景(例如有些 API 要查資料庫很久)。
3. IP Hash(IP 雜湊)
Client A (IP: 1.2.3.4) → Hash → 永遠送到 Server 2
Client B (IP: 5.6.7.8) → Hash → 永遠送到 Server 1
Client C (IP: 9.0.1.2) → Hash → 永遠送到 Server 3
Code language: CSS (css)翻譯:根據 Client 的 IP 算出一個固定值,永遠送到同一台伺服器。
適合:需要維持 Session 的場景(例如使用者登入後,後續請求都要送到同一台)。
注意:這種做法犧牲了一些負載平衡的效果,因為不是「誰最閒就給誰」。
最小範例:Nginx 設定你會看到什麼
# Nginx 作為 Load Balancer 的設定
upstream my_app {
# 預設就是 Round Robin
server 192.168.1.10:8080; # Server 1
server 192.168.1.11:8080; # Server 2
server 192.168.1.12:8080; # Server 3
}
server {
listen 80;
location / {
proxy_pass http://my_app; # 把請求轉發給上面定義的伺服器群
}
}
Code language: PHP (php)逐段翻譯:
upstream my_app:定義一組後端伺服器,取名叫my_appserver 192.168.1.10:8080:後端伺服器 1 的位置proxy_pass http://my_app:收到請求時,轉發給my_app這組伺服器(Nginx 會自動用 Round Robin 分配)
如果要用其他演算法:
upstream my_app {
least_conn; # ← 改用 Least Connections
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
Code language: PHP (php)upstream my_app {
ip_hash; # ← 改用 IP Hash
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
Code language: PHP (php)翻譯:只要在 upstream 區塊裡加一行,就能切換分配策略。不加的話預設就是 Round Robin。
雲端平台的 Load Balancer
在實際場景中,你不一定要自己設定 Nginx。雲端平台都有現成的 Load Balancer 服務:
| 雲端平台 | Load Balancer 服務 | 你會看到的名稱 |
|---|---|---|
| AWS | Elastic Load Balancing | ALB(Application LB)、NLB(Network LB) |
| GCP | Cloud Load Balancing | HTTP(S) Load Balancer |
| Azure | Azure Load Balancer | Application Gateway |
翻譯:這些本質上都在做同一件事 —— 把流量分散到多台伺服器。只是名字不同、設定介面不同。
垂直 vs 水平:怎麼選?
這是面試和實務中最常被問的問題。用一張表總結:
| 考量因素 | 垂直擴展(Scale Up) | 水平擴展(Scale Out) |
|---|---|---|
| 做法 | 換更大的機器 | 加更多台機器 |
| 難度 | 簡單,不改架構 | 複雜,要處理分散式問題 |
| 上限 | 有(硬體規格有天花板) | 理論上無限 |
| 可用性 | 低(單點故障) | 高(一台掛了還有其他台) |
| 成本 | 高規格機器單價很貴 | 多台小機器可能更划算 |
| 適合 | 初期、DB、流量穩定 | 成長期、Web Server、流量波動大 |
實務上的選擇邏輯
流量不夠了,怎麼辦?
│
├─ 先試垂直擴展(最簡單)
│ ├─ 夠用了 → 結束
│ └─ 還是不夠 / 需要高可用性 → 往下
│
└─ 做水平擴展
├─ 加 Load Balancer
├─ 處理 Session / State 問題
└─ 設定自動擴展(Auto Scaling)
翻譯:大多數情況下,先 Scale Up 是最務實的做法。等到 Scale Up 到頂了,或是你需要「不能停機」的保證,再考慮 Scale Out。
Vibe Coder 檢查點
當你在架構圖、部署設定、或是 AI 的建議中看到這些概念時,確認以下幾點:
- [ ] 看到 Scale Up 建議時:確認是否真的只是流量問題。有時候應用變慢是因為程式碼效能差(比如沒加 index 的資料庫查詢),Scale Up 只是治標。
- [ ] 看到 Scale Out 建議時:確認你的應用是否是 Stateless 的。如果 Session 存在伺服器記憶體裡,Scale Out 後會出問題。
- [ ] 看到 Load Balancer 設定時:確認使用的演算法是否適合你的場景。大多數情況 Round Robin 就夠了,除非你有特殊需求。
- [ ] 看到
replicas或Auto Scaling設定時:確認 min 和 max 的值是否合理。設太高會浪費錢,設太低會擋不住流量。
必看懂 vs 知道就好
必看懂(會一直出現)
- 垂直 vs 水平擴展的差異 —— 這是所有擴展討論的基礎
- Load Balancer 的角色 —— 只要有多台伺服器就會出現
- Round Robin —— 最常見的預設分配方式
- Stateless 設計的重要性 —— 水平擴展的前提條件
知道就好(遇到再查)
- Sticky Sessions:讓 Load Balancer 記住某個使用者要送到哪台伺服器,是 IP Hash 的變體
- Health Check:Load Balancer 定期檢查後端伺服器是否活著,壞掉的就不送請求過去
- Connection Draining:要關掉一台伺服器前,等它處理完手上的請求再關
- Weighted Round Robin:給不同伺服器不同的權重,效能好的多分一點請求
本篇重點回顧
系統擴展三步驟:
1. Vertical Scaling(垂直擴展)
→ 把機器變強:升級 CPU、RAM
→ 簡單但有上限
2. Horizontal Scaling(水平擴展)
→ 多開幾台機器分擔工作
→ 沒上限但架構複雜,需要處理 State 問題
3. Load Balancer(負載均衡器)
→ 水平擴展後必備,分配請求到各台伺服器
→ 常見演算法:Round Robin / Least Connections / IP Hash
下一篇,我們會看 Caching(快取) —— 另一個讓系統變快的關鍵手段。不是所有請求都需要每次重新計算,有些結果可以「記住」。
**本文整理自**:[System Design was HARD until I Learned these 30 Concepts](https://www.youtube.com/watch?v=YyOXt2MEkA4) by Ashish Pratap Singh
**系列目錄**:系統設計 30 概念(共 6 篇)
進階測驗:系統擴展與負載均衡
共 5 題,包含情境題與錯誤診斷題。