【系統設計 30 概念】#03 系統擴展與負載均衡 — 當一台伺服器不夠用

測驗:系統擴展與負載均衡

共 5 題,點選答案後會立即顯示結果

1. Vertical Scaling(垂直擴展)的做法是什麼?

  • A. 增加更多台伺服器來分擔工作量
  • B. 升級現有伺服器的 CPU、RAM 等硬體規格
  • C. 在伺服器前面加一個 Load Balancer
  • D. 將應用程式改寫為分散式架構

2. 水平擴展(Horizontal Scaling)相較於垂直擴展,最大的優勢是什麼?

  • A. 架構最簡單,不需要修改程式碼
  • B. 不需要處理資料一致性的問題
  • C. 理論上沒有擴展上限,且提供冗餘能力(一台掛了還有其他台)
  • D. 成本一定比垂直擴展低

3. Load Balancer 使用 Round Robin 演算法時,請求是如何分配的?

  • A. 根據 Client 的 IP 位址固定分配到同一台伺服器
  • B. 優先分配給目前連線數最少的伺服器
  • C. 隨機選擇一台伺服器處理請求
  • D. 依序輪流分配給每台伺服器,一人一次

4. 水平擴展後,如果使用者登入狀態(Session)存在伺服器記憶體裡,會發生什麼問題?

  • A. 所有伺服器會自動同步 Session 資訊
  • B. 使用者的下一個請求如果被送到不同伺服器,該伺服器不知道使用者已登入
  • C. Load Balancer 會自動將 Session 傳遞給所有伺服器
  • D. 使用者需要在每台伺服器上分別登入

5. 以下 Nginx 設定片段的作用是什麼?

upstream my_app { least_conn; server 192.168.1.10:8080; server 192.168.1.11:8080; server 192.168.1.12:8080; }
  • A. 定義三台伺服器,使用 Round Robin 輪流分配請求
  • B. 定義三台伺服器,根據 Client IP 固定分配到同一台
  • C. 定義三台伺服器,將新請求分配給目前連線數最少的那台
  • D. 定義三台伺服器,隨機選擇一台來處理每個請求

**系列**:系統設計 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_limitcpus
# 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_app
  • server 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 就夠了,除非你有特殊需求。
  • [ ] 看到 replicasAuto 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 題,包含情境題與錯誤診斷題。

1. 你的 Web 應用部署在一台 t3.small(2 vCPU, 2GB RAM)上,最近開始出現回應變慢的情況。目前日流量穩定在每天 5000 次請求,短期內不會有大幅變動。你應該怎麼做? 情境題

  • A. 立刻做水平擴展,開 3 台伺服器並加上 Load Balancer
  • B. 先垂直擴展,升級到更大的 instance type(例如 t3.xlarge)
  • C. 加入 Kubernetes 並設定 HPA 自動擴展
  • D. 使用 IP Hash 演算法的 Load Balancer 來分散流量

2. 你的電商網站有些 API 回應很快(商品列表,約 50ms),有些很慢(訂單查詢需要複雜的資料庫計算,約 3 秒)。你已經水平擴展到 4 台伺服器,但發現某些伺服器經常過載而其他伺服器很閒。目前使用 Round Robin 分配。你應該怎麼調整? 情境題

  • A. 增加更多伺服器數量,從 4 台擴展到 8 台
  • B. 改用 IP Hash,讓每個使用者固定在同一台伺服器上
  • C. 改用 Least Connections 演算法,讓新請求分配給目前最閒的伺服器
  • D. 對所有伺服器做垂直擴展,升級到更高的硬體規格

3. 你的應用使用了 3 台伺服器做水平擴展,使用者反映「有時候登入後再操作就變成未登入狀態」。你檢查發現應用是把 Session 存在每台伺服器各自的記憶體裡。以下哪個方案最能根本解決這個問題? 情境題

  • A. 把 Load Balancer 改用 IP Hash,讓同一個使用者永遠送到同一台伺服器
  • B. 增加伺服器數量到 5 台以減少單台負載
  • C. 對現有 3 台伺服器做垂直擴展,讓它們處理得更快
  • D. 將 Session 改存到獨立的 Redis,或改用 JWT Token 實作無狀態設計

4. 團隊成員設定了以下 Nginx Load Balancer,但使用者回報「每次重新整理頁面都要重新登入」。這個設定最可能的問題在哪裡? 錯誤診斷

upstream my_app { server 192.168.1.10:8080; server 192.168.1.11:8080; server 192.168.1.12:8080; } server { listen 80; location / { proxy_pass http://my_app; } }
  • A. listen 80 應該改成 listen 443 才能支援 HTTPS
  • B. 使用了預設的 Round Robin,Session 存在伺服器記憶體時,使用者請求可能被送到不同伺服器導致 Session 遺失
  • C. 三台伺服器的 IP 位址設定錯誤,應該使用公網 IP
  • D. 缺少 least_conn 指令導致負載分配不均

5. 團隊部署了以下 Kubernetes HPA 設定,但發現在流量高峰期(CPU 使用率飆到 95%)應用仍然很慢,HPA 卻沒有繼續增加機器。最可能的原因是什麼? 錯誤診斷

apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler spec: minReplicas: 2 maxReplicas: 3 metrics: – type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70
  • A. averageUtilization: 70 的閾值設定太低,應該調高到 90
  • B. 應該改用 minReplicas: 1 才能讓 HPA 有更大的調整空間
  • C. maxReplicas: 3 設定太低,已經達到上限無法再增加,應該調高 maxReplicas
  • D. HPA 只能監控記憶體使用率,無法根據 CPU 使用率自動擴展

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *