測驗:擴展與效能 — Scaling、Load Balancer、CDN、Caching
共 5 題,點選答案後會立即顯示結果
1. Vertical Scaling(垂直擴展)的主要缺點是什麼?
2. CDN 最適合用來快取哪一類資源?
3. Load Balancer 使用 Least Connections 策略時,新的請求會被分配到哪裡?
4. 在下面的 Redis 快取程式碼中,ex=3600 的作用是什麼?
5. 在電商網站的完整架構中,CDN、Load Balancer 和 Cache 三者協作後,資料庫實際需要處理的流量大約是原本的多少?
本篇是「系統設計 20 概念」系列第 3 篇,共 5 篇。
難度:L2-進階 | 前置知識:第 1 篇的網路基礎(IP、HTTP)
一句話說明
當使用者暴增、伺服器撐不住時,我們有四種武器:加大機器、增加機器、把內容放近一點、把結果記起來。
問題場景:雙 11 你的網站掛了
想像你經營一個電商網站,平常每秒 100 個請求,一切正常。
雙 11 來了,每秒 10,000 個請求湧入。你的單台伺服器:
- CPU 飆到 100%
- 記憶體用光
- 資料庫連線數爆滿
- 使用者看到 502 Bad Gateway
怎麼辦?
這篇要講的四個概念,就是解決這個問題的四把鑰匙。先看一下它們在架構中的位置:
使用者(台北) 使用者(高雄) 使用者(東京)
| | |
v v v
[ CDN 邊緣節點 — 靜態資源直接回應 ] ← (3) CDN
|
v
[ Load Balancer — 分配流量 ] ← (2) Load Balancer
| | |
v v v
Server A Server B Server C ← (1) Horizontal Scaling
| | |
v v v
[ Cache 層(Redis) ] ← (4) Caching
|
v
[ Database ]
接下來逐一拆解。
概念 1:Scaling(擴展)
一句話翻譯
伺服器扛不住了,要嘛換更大台,要嘛多叫幾台來幫忙。
兩種擴展方式
Vertical Scaling(垂直擴展)= 升級單台機器
升級前: 升級後:
┌──────────┐ ┌──────────────┐
│ 4 CPU │ →→→ │ 32 CPU │
│ 8GB RAM │ │ 128GB RAM │
│ 500GB SSD│ │ 2TB NVMe SSD │
└──────────┘ └──────────────┘
舊機器 新猛獸
白話翻譯:把你的筆電換成工作站。CPU 加大、記憶體加多、硬碟換快的。
優點:
- 最簡單,不用改程式碼
- 不用處理多台機器的協調問題
缺點:
- 有天花板(一台機器最多就那麼大)
- 單點故障 — 這台掛了,全部掛
Horizontal Scaling(水平擴展)= 多叫幾台來
擴展前: 擴展後:
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Server │ →→→ │ Server A │ │ Server B │ │ Server C │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
一台扛 三台分著扛
白話翻譯:搬家太重?不是找一個大力士,而是多叫幾個人一起搬。
優點:
- 理論上無上限(不夠就再加)
- 一台壞了還有其他台頂著
缺點:
- 程式要能跑在多台機器上(不能把資料存在本地)
- 需要有人「分配工作」— 這就是下面的 Load Balancer
必看懂 vs 知道就好
| 概念 | 重要性 |
|---|---|
| Vertical = 升級單台 | 必看懂 |
| Horizontal = 加機器 | 必看懂 |
| Vertical 有天花板 | 必看懂 |
| Horizontal 需要 stateless 設計 | 知道就好,遇到再查 |
面試怎麼問
「你的系統使用者從 1 萬成長到 100 萬,你會怎麼做?」
標準答案起手式:先 Vertical Scaling 到合理上限,然後轉 Horizontal Scaling。
概念 2:Load Balancer(負載均衡器)
一句話翻譯
站在門口的交通指揮,把客人平均分配到不同櫃台。
工作原理
所有請求
|
v
┌─────────────────┐
│ Load Balancer │ ← 「你去 A,你去 B,你去 C」
└─────────────────┘
| | |
v v v
Server Server Server
A B C
沒有 Load Balancer 的時候,所有流量打到同一台 Server。有了它,流量被分散,每台伺服器只要扛 1/3。
常見的分配策略
策略 1:Round Robin(輪流)
請求 1 → Server A
請求 2 → Server B
請求 3 → Server C
請求 4 → Server A ← 回到第一台,繼續輪
請求 5 → Server B
...
白話翻譯:排隊叫號,一人一次,輪流來。
最簡單的策略。問題是:如果 Server A 已經很忙、Server B 很閒,它不會管,照樣輪。
策略 2:Least Connections(最少連線)
Server A: 正在處理 15 個請求
Server B: 正在處理 3 個請求 ← 新請求送這裡
Server C: 正在處理 10 個請求
白話翻譯:看誰最閒就派給誰。
比 Round Robin 聰明,會看目前各伺服器的負載狀況。
策略 3:IP Hash(依 IP 分配)
使用者 IP: 1.2.3.4 → hash → 結果: A → 永遠去 Server A
使用者 IP: 5.6.7.8 → hash → 結果: B → 永遠去 Server B
Code language: CSS (css)白話翻譯:同一個客人永遠去同一個櫃台。
適用於需要「黏性 Session」的場景(例如使用者登入狀態存在特定伺服器上)。
在程式碼中長什麼樣
你如果用 AI 協助開發,可能會在 Nginx 設定檔裡看到這樣的內容:
upstream backend {
# 列出所有後端伺服器
server 10.0.0.1:8080; # Server A
server 10.0.0.2:8080; # Server B
server 10.0.0.3:8080; # Server C
}
server {
listen 80; # 對外只開一個入口
location / {
proxy_pass http://backend; # 把流量轉給上面那組伺服器
}
}
Code language: PHP (php)逐行翻譯:
upstream backend— 定義一組後端伺服器,取名叫 backendserver 10.0.0.1:8080— 第一台伺服器的 IP 和 portproxy_pass http://backend— 把進來的請求轉發給那組伺服器(Nginx 預設用 Round Robin)
雲端服務中的 Load Balancer
在實際工作中,你不一定會自己設定 Nginx。雲端平台都有現成的:
| 雲端平台 | 服務名稱 |
|---|---|
| AWS | Elastic Load Balancing (ELB) |
| GCP | Cloud Load Balancing |
| Azure | Azure Load Balancer |
它們做的事情一樣 — 分配流量。差別在有更多進階功能(健康檢查、自動移除壞掉的伺服器等)。
概念 3:CDN(Content Delivery Network)
一句話翻譯
把你的圖片、CSS、JS 複製到全世界各地的伺服器,讓使用者從最近的地方拿。
為什麼需要 CDN
沒有 CDN:
東京使用者 → (海底電纜) → 美國主機 → 回傳圖片
延遲: 200ms+
有 CDN:
東京使用者 → 東京邊緣節點 → 直接回傳圖片
延遲: 20ms
物理距離決定速度。光速是有限的,從東京到美國再回來就是慢。CDN 的解法很直覺:把東西放到離使用者近的地方。
CDN 的運作方式
第一次存取(Cache Miss):
使用者 → CDN 邊緣節點 → 「我沒有這張圖」→ 回源站拿 → 存一份 → 回傳給使用者
第二次存取(Cache Hit):
使用者 → CDN 邊緣節點 → 「我有!」→ 直接回傳
- 使用者請求一張圖片
- CDN 邊緣節點檢查自己有沒有
- 沒有(Miss)→ 去原始伺服器拿,存下來,回傳
- 有(Hit)→ 直接回傳,不用問原始伺服器
CDN 適合放什麼
適合(靜態、不常變): 不適合(動態、常變):
✅ 圖片 (.jpg, .png, .webp) ❌ 使用者個人資料
✅ CSS 樣式檔 ❌ 購物車內容
✅ JavaScript 檔案 ❌ 即時聊天訊息
✅ 影片串流 ❌ 股票報價
✅ 字型檔案
Code language: CSS (css)判斷原則:內容是「給所有人看都一樣」的,就適合放 CDN。
在程式碼中長什麼樣
你在前端專案裡可能會看到 CDN 的引用方式:
<!-- 從 CDN 載入 jQuery(不是從自己的伺服器) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
<!-- 從 CDN 載入字型 -->
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+TC" rel="stylesheet">
Code language: HTML, XML (xml)翻譯:這些檔案不是放在你的伺服器上,而是從 CDN 全球節點載入。使用者會自動連到離他最近的那個節點。
常見 CDN 服務
| 服務 | 特色 |
|---|---|
| Cloudflare | 免費方案夠用,最多人用 |
| AWS CloudFront | 和 AWS 生態整合 |
| Akamai | 老牌,企業級 |
| Fastly | 開發者友善,邊緣運算 |
概念 4:Caching(快取)
一句話翻譯
把之前算過的結果記起來,下次直接用,不要重算。
為什麼需要快取
沒有快取:
請求 → 伺服器 → 查資料庫(50ms)→ 計算結果(20ms)→ 回傳
每次都要 70ms
有快取:
請求 → 伺服器 → 查快取(1ms)→ 有!→ 回傳
只要 1ms
同樣的查詢,資料庫要 50ms,快取只要 1ms。差 50 倍。
當你的網站每秒 10,000 個請求,其中 80% 在看同樣的商品頁面時,快取就是救命稻草。
快取的不同層級
快取不只一種,它出現在整個架構的每一層:
使用者的瀏覽器
↓ [瀏覽器快取] ← 第 1 層:最快,直接不發請求
CDN 邊緣節點
↓ [CDN 快取] ← 第 2 層:靜態資源
Load Balancer
↓
應用伺服器
↓ [應用層快取] ← 第 3 層:Redis / Memcached
資料庫
[查詢快取] ← 第 4 層:資料庫自己的快取
第 1 層:瀏覽器快取
HTTP/1.1 200 OK
Cache-Control: max-age=86400 ← 告訴瀏覽器「這個資源 24 小時內不用再問我」
Content-Type: image/jpeg
Code language: HTTP (http)翻譯:伺服器在回應裡加一個 header,告訴瀏覽器「這個東西 86400 秒(24 小時)內不會變,你存起來直接用」。
第 2 層:CDN 快取
就是上面 CDN 章節講的那個機制。靜態資源由邊緣節點快取。
第 3 層:應用層快取(Redis / Memcached)
這是最常見的後端快取方案。如果 AI 幫你寫後端,你很可能會看到這樣的程式碼:
import redis
cache = redis.Redis(host='localhost', port=6379) # 連線到 Redis
def get_product(product_id):
# 第 1 步:先查快取
cached = cache.get(f"product:{product_id}") # 用 key 去查
if cached:
return json.loads(cached) # 有!直接回傳
# 第 2 步:快取沒有,查資料庫
product = db.query(f"SELECT * FROM products WHERE id = {product_id}")
# 第 3 步:存進快取,下次就有了
cache.set(f"product:{product_id}", json.dumps(product), ex=3600) # ex=3600 表示 1 小時後過期
return product
Code language: PHP (php)逐行翻譯:
cache.get(...)— 去 Redis 查有沒有快取過的資料if cached: return— 有就直接回傳(超快,1ms 以內)db.query(...)— 沒有才去查資料庫(慢,50ms+)cache.set(..., ex=3600)— 查完存進 Redis,設定 1 小時後過期
這個「先查快取 → 沒有就查資料庫 → 存回快取」的套路,叫做 Cache-Aside Pattern。你在 90% 的後端程式碼中都會看到這個模式。
第 4 層:資料庫查詢快取
資料庫自己也會快取常見的查詢結果。這部分通常不需要你處理,知道存在就好。
快取的致命問題:資料不一致
快取最大的問題:資料過期了怎麼辦?
時間線:
t=0 商品價格 = $100,快取也存了 $100
t=5 管理員把價格改成 $80(資料庫更新了)
t=10 使用者看到的還是 $100(因為快取沒更新)← 問題!
常見的解決策略:
| 策略 | 做法 | 適合場景 |
|---|---|---|
| TTL(存活時間) | 設定過期時間,過期自動刪除 | 大部分場景 |
| Write-Through | 寫資料庫的同時也寫快取 | 讀多寫少 |
| Cache Invalidation | 資料更新時主動刪除快取 | 對一致性要求高 |
最常見的做法是 TTL — 設定一個合理的過期時間(例如 5 分鐘),過期後自動重新查資料庫。簡單粗暴但有效。
四個概念如何協作
回到雙 11 場景,完整的解決方案:
使用者想買一雙鞋
|
v
[CDN] → 商品圖片、CSS、JS 直接從邊緣節點回傳 → 省 80% 靜態請求
|
v
[Load Balancer] → 把動態請求分散到 5 台伺服器 → 每台只扛 1/5
|
v
[Server A~E] → 查商品資訊
|
v
[Redis Cache] → 快取裡有!直接回傳 → 省 90% 資料庫查詢
|(只有快取沒有的才到這步)
v
[Database] → 只處理真正需要的查詢
效果:
- CDN 攔截了 80% 的靜態資源請求
- Load Balancer 把剩下的請求分散到多台伺服器
- 快取攔截了 90% 的資料庫查詢
- 資料庫實際只需要處理原本 2% 的流量
這就是為什麼蝦皮、PChome 這些電商平台能撐住每年的雙 11 — 不是因為有一台超級電腦,而是靠這套組合拳。
Vibe Coder 檢查點
當你在專案中看到這些概念時,確認以下事項:
看到 Scaling 相關設定時:
- [ ] 目前是 Vertical 還是 Horizontal?有沒有遇到瓶頸的風險?
- [ ] 如果是 Horizontal,應用程式是不是 stateless 的?(不把使用者資料存在單台伺服器記憶體裡)
看到 Load Balancer 設定時:
- [ ] 用的是什麼分配策略?Round Robin 對你的場景夠用嗎?
- [ ] 有沒有設定健康檢查?(某台伺服器掛了要自動跳過)
看到 CDN 設定時:
- [ ] 靜態資源有沒有走 CDN?如果全都從自己的伺服器送,效能會很差
- [ ] CDN 的快取時間設多久?太長會導致更新後使用者看到舊版本
看到 Cache 相關程式碼時:
- [ ] 有設定 TTL(過期時間)嗎?沒有的話快取永遠不會更新
- [ ] 快取的 key 命名有沒有意義?(例如
product:123比cache_1好) - [ ] 有處理 Cache Miss 的情況嗎?(快取沒有時要能正常從資料庫查)
本篇重點回顧
| 概念 | 一句話 | 什麼時候用 |
|---|---|---|
| Vertical Scaling | 升級單台機器 | 初期最簡單的做法 |
| Horizontal Scaling | 加更多機器 | 流量大到單台扛不住 |
| Load Balancer | 把流量分散到多台 | 用了 Horizontal Scaling 就需要 |
| CDN | 靜態資源放到全球各地 | 使用者分散在不同地區 |
| Caching | 把算過的結果記起來 | 同樣的資料被反覆請求 |
**面試小提示**:系統設計面試中,「你的系統怎麼 Scale?」幾乎是必問題。回答套路:先 Vertical Scaling,遇到瓶頸後 Horizontal Scaling + Load Balancer,加上 CDN 處理靜態資源、Cache 減少資料庫壓力。這四個概念是組合技,不是單選題。
延伸:知道就好
這些進階主題在面試中偶爾出現,先知道名字就好:
- Auto Scaling:根據流量自動增減伺服器數量(雲端平台都有支援)
- Reverse Proxy:和 Load Balancer 類似,但還能做安全過濾、SSL 終止等
- Cache Stampede:快取過期的瞬間大量請求同時打到資料庫,造成雪崩
- Consistent Hashing:Horizontal Scaling 時更聰明的分配演算法,減少重新分配
- Write-Behind Cache:先寫快取再非同步寫資料庫,提升寫入效能但有資料遺失風險
進階測驗:擴展與效能 — Scaling、Load Balancer、CDN、Caching
共 5 題,包含情境題與錯誤診斷題。