iT邦幫忙

2026 iThome 鐵人賽

DAY 3
0

當一個系統剛上線時,使用者可能只有幾百人。
每天只有幾千筆 Request,也許一台 Server 就可以處理所有工作。
但如果有一天:

100 個使用者 -> 10,000 個使用者-> 1,000,000 個使用者

系統還撐得住嗎?

這就是今天要討論 Scalability(可擴展性),它關心的並不是:

「系統現在能不能跑?」

而是:

當業務量持續成長時,系統能不能透過增加資源,繼續維持可以接受的服務品質?

這裡有兩個很重要的觀察指標:

  • Throughput
  • Latency

Throughput:系統能處理多少工作?

Throughput 可以理解成:

單位時間內,系統能完成多少工作。

例如:

Requests Per Second(RPS)
Transactions Per Second(TPS)
Messages Per Second

如果今天是一個電商系統,Throughput 可能代表:

每秒可以建立多少筆訂單

如果今天是一個支付系統,可能代表:

每秒可以處理多少筆交易

假設原本系統可以處理:

1,000 TPS

平常公司只有:

300 TPS

看起來完全沒有問題。

但活動開始後突然變成:

2,000 TPS

系統開始出現:

Queue 堆積
Timeout
Error
CPU 100%
Database Connection 耗盡

對工程師來說,這叫:

Throughput 不足。

但對公司來說可能只是:

老闆收不到訂單。

對使用者來說則是:

「為什麼一直下不了單?」

所以 Throughput 並不只是技術指標。

它其實代表:

系統能不能承接公司的業務量。


Latency:處理得了,不代表使用者願意等

另一個重要指標是:

Latency

Latency 指的是:

從 Request 發出去,到收到 Response 所需要的時間。

例如:

GET /orders/123

如果花 100 ms,使用者通常感覺不到。變成 500 ms 大多數情況可能還可以接受。

但如果變成 5 秒,使用者就可能開始想,「是不是壞掉了?」,甚至我們自己也可以換位思考一下,你自己可以接受嗎?

所以系統不是只要做得完就可以。它還要在合理時間內做完。


Average Latency 不一定可靠

假設 Monitoring 顯示:

Average Latency = 200 ms

乍看之下很正常,但實際上可能是:

90% Request = 100 ms
9% Request  = 500 ms
1% Request  = 10 秒

平均值仍然可能很好看。

但是那最後的 1% 使用者體驗可能非常差。

所以實務上我們還會觀察:

p50
p95
p99

例如:

p50 = 100 ms
p95 = 300 ms
p99 = 2 sec

可以理解成:

50% Request 在 100 ms 內完成
95% Request 在 300 ms 內完成
99% Request 在 2 秒內完成

因此在討論 Scalability 時,真正要觀察的不是:

「Server 有沒有掛掉?」

而是:

流量增加之後,Throughput 能不能增加,同時 Latency 還能維持在合理範圍?


Scalability 到底在解決什麼?

假設目前系統:

10 萬會員
500 TPS
p95 = 200 ms

一年後變成:

100 萬會員
5,000 TPS

我們希望系統仍然可以保持:

p95 < 300 ms
Error Rate < 0.1%

如果做得到,就代表這個系統具有一定程度的可擴展性。

這時候最常見的兩種方法就是:

Vertical Scaling
Horizontal Scaling

也就是:

垂直擴充
水平擴充

我認為可以先簡單理解一下,一個是要求現在的員工能力更強,另外是多請一個能力差不多的員工


垂直擴充 Vertical Scaling

垂直擴充其實很好理解。

原本:

4 Core
8 GB RAM

升級成:

8 Core
16 GB RAM

再不夠就:

16 Core
32 GB RAM

簡單來說就是:

把同一台機器變得更強。

我自己通常會認為:

在系統規模還沒有大到需要 Distributed System 時,可以優先考慮 Vertical Scaling。

原因很簡單,成本考量

不是一定每個月花的錢比較便宜,而是工程成本通常比較低。

例如原本:

Application
    │
    ▼
Database

CPU 不夠:

4 Core
↓
8 Core

可能就解決了。

不用增加:

Load Balancer
Distributed Lock
Distributed Cache
Service Discovery

整體架構仍然相對單純。


水平擴充 Horizontal Scaling

Horizontal Scaling 則不是:

把機器變強。

而是:

增加更多機器一起處理工作。

原本:

Client
  │
  ▼
Server

變成:

            ┌── Server A
Client → LB ├── Server B
            └── Server C

例如:

每台 Server = 1,000 RPS

理想情況下:

1 台 = 1,000 RPS
2 台 = 2,000 RPS
4 台 = 4,000 RPS

這就是 Scale Out。

但是實際世界通常沒有這麼漂亮。


水平擴充不是免費的

假設原本系統只有一台 Server:

Server A

現在變成:

Server A
Server B
Server C

很多原本不存在的問題就會跑出來。

例如:

Session 放在哪裡?

如果 Session 存在 Server A:

Request 1 → Server A
Request 2 → Server B

Server B 可能完全不知道使用者登入過。

因此可能開始需要:

Redis
Distributed Cache

排程 Job 誰執行?

假設每台 Server 都會執行:

RefundJob

那:

Server A → Refund
Server B → Refund
Server C → Refund

同一筆退款可能被執行三次。

因此又可能需要:

Idempotency
Distributed Lock
Leader Election

所以 Horizontal Scaling 的真正成本通常不是:

多一台 Server 要多少錢。

而是:

當系統開始成為 Distributed System 後,會產生多少額外複雜度。


那什麼時候需要水平擴充?

不是看到 CPU 高就一定要加 Server。

比較合理的是觀察幾個訊號。


1. 單機已經接近資源上限

例如:

CPU 85%
Memory 90%

而且不是瞬間 Spike,而是長時間維持高負載。

這代表單機可能已經接近 Saturation。


2. Scale Up 的成本效益開始下降

例如:

8 Core → 16 Core

價格增加還算合理。

但是:

16 Core → 32 Core

價格可能大幅增加。

而效能卻不會線性成長。

這時候:

2 × 16 Core

可能比:

1 × 32 Core

更有彈性。

這就是:

Vertical Scaling 的邊際效益開始下降。


3. 單台 Server 已經變成 Single Point of Failure

即使 Performance 完全沒問題:

CPU = 30%
Memory = 40%

但是如果系統只有:

1 台 Server

那:

Server Crash
Deployment Failure
OS Update
Hardware Failure

都有可能讓整個服務中斷。

所以有時候做 Horizontal Scaling 並不是因為 Performance。

而是因為:

Availability。

例如:

Server A ❌
Server B ✅

其中一台失效,另外一台仍然可以提供服務。


4. Traffic 波動很大

假設平常:

500 RPS

活動期間:

5,000 RPS

如果全部依靠 Vertical Scaling,就代表平常也必須維持一台:

可以承受 5,000 RPS

的高規格 Server。

但是大部分時間:

90% Resource 都沒被使用。

如果是 Horizontal Scaling:

平常:
2 Instances

活動:
10 Instances

活動結束再 Scale In。

這也是 Auto Scaling 常見的使用情境。


Vertical Scaling 和 Horizontal Scaling 不是二選一

實務上通常不是:

Scale Up
VS
Scale Out

而是:

Scale Up
+
Scale Out

例如:

2 Core
↓
4 Core
↓
8 Core

先做 Vertical Scaling。

當單機繼續升級已經不划算:

8 Core × 1
↓
8 Core × 2
↓
8 Core × 4

再逐漸走向 Horizontal Scaling。

所以比較合理的思路不是:

一開始就建立一套很複雜的 Distributed System。

而是:

隨著業務成長,逐步增加系統可以承受的 Capacity。


Horizontal Scaling 一定能增加 Throughput 嗎?

不一定。

假設:

1 App Server = 1,000 RPS

理論上:

2 台 = 2,000
4 台 = 4,000

但實際上可能是:

1 台 = 1,000 RPS
2 台 = 1,800 RPS
4 台 = 2,500 RPS

為什麼?

因為 Bottleneck 可能已經不在 Application Server。

而在:

Database
Redis
Message Queue
Network
3rd Party API

例如:

              ┌── App
              ├── App
Client → LB ──┼── App
              ├── App
              └── App
                   │
                   ▼
                Database

App Server 可以一直增加。

但 Database 只有一台。

最後可能變成:

App CPU = 20%

Database CPU = 100%

這時候繼續增加 App Server 根本沒有意義。

所以 Scalability 最核心的一件事其實是:

找出 Bottleneck。


Throughput 與 Latency 要一起看

假設 Load Test 結果如下:

100 RPS
p95 = 100 ms

500 RPS
p95 = 120 ms

1,000 RPS
p95 = 180 ms

1,500 RPS
p95 = 500 ms

2,000 RPS
p95 = 3 sec

你會發現一件事情:

在某個時間點以前:

Traffic ↑
Throughput ↑
Latency 維持穩定

但到某個時間點之後:

Traffic ↑
Latency ↑↑↑

這代表系統開始進入 Saturation。

接下來可能出現:

Queue ↑
Timeout ↑
Retry ↑
Connection ↑

甚至最後:

Throughput ↓

所以:

最大 TPS 並不是最有意義的 Capacity 指標。

真正應該問的是:

在我們可以接受的 Latency 與 Error Rate 下,系統可以穩定處理多少 Traffic?

例如:

最大測試結果:
2,000 TPS

但是:

p95 = 5 sec

這不能真的說:

「我們系統可以扛 2,000 TPS。」

如果公司要求:

p95 < 500 ms

那真正可用的 Capacity 可能只有:

1,500 TPS

甚至更低。


Scalability 不只是加機器

很多人第一次接觸 Scalability,可能會直覺想到:

Server 不夠
→
多開幾台

但真正的 Scalability 應該是在思考:

Traffic 增加
↓
哪個 Component 先到極限?
↓
能不能透過增加資源提升 Capacity?
↓
增加資源之後 Bottleneck 移到哪裡?

例如:

App
↓
Database
↓
Cache
↓
Message Queue
↓
3rd Party

Scalability 很像是不斷在追逐 Bottleneck。

因為 Bottleneck 不會真正消失。

它只會:

移動到下一個地方。


事先規劃勝於臨時治療

系統真正危險的不是:

現在只有 500 TPS。

而是:

沒有人知道 1,000 TPS 時會發生什麼事情。

如果完全沒有:

Monitoring
Load Test
Capacity Planning

通常要等到 Production 出現:

CPU 100%
Connection Pool 滿
Queue 堆積
Timeout 爆炸

才開始調查。

這時候就不是:

Scalability Planning

而是:

Incident Handling。

比較健康的做法,是提前知道:

Current Traffic
Peak Traffic
Max Throughput
p95 / p99 Latency
Error Rate
CPU
Memory
DB Connection
Queue Lag

然後保留一定程度的:

Headroom

例如系統在:

2,000 TPS

就開始大幅惡化。

那我們通常不會真的讓 Production 長期跑在:

1,950 TPS

才開始處理。

而可能在:

1,200 ~ 1,500 TPS

就開始規劃下一階段的 Capacity。

因為真實世界的 Traffic 不會永遠穩定。


問題思考

目前有一台 Application Server:

CPU = 20%
Memory = 30%

效能完全足夠。

但是只要這台 Server 掛掉,整個服務就會中斷。

這時候新增第二台 Server。

主要是在改善:Scalability?還是 Availability?

Load Test 結果:

1,000 TPS
p95 = 200 ms

1,500 TPS
p95 = 400 ms

2,000 TPS
p95 = 5 sec

Production Peak Traffic 已經來到:

1,300 TPS

你會等到:

2,000 TPS

才開始做 Scaling 嗎?還是應該提前開始 Capacity Planning?


上一篇
Day 2 - 分散式系統的取捨 - CAP 定理
系列文
30 天理解大型系統設計:核心技術與架構思維4
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言