---
# System prepended metadata

title: SCALE FROM ZERO to MILLION of USERS P1
tags: [SD Interview]

---

# SCALE FROM ZERO to MILLION of USERS

## 何謂系統？

維基百科對「系統」（System）的定義是：
「一群有關聯的個體，根據某種規則運作，能完成單一元件無法獨立達成的任務。」簡單說，系統就是「讓許多部分協作」的結構。

做一個只有自己在用的系統很簡單。
但當使用者數量上升，一切都變了。

想想你每天滑的 Threads —— 你看到的內容可能和別人不一樣，有時還會延遲。
或者像 AWS 當機時，Canva、Duolingo 全部無法使用。

這些都是「系統設計」要解決的問題：
**當使用者從 1 個變成 100 萬個時，系統要如何保持穩定、快速又一致？**

---

## Single Server Setup（單一伺服器架構）

再怎麼大的系統，一開始都只是在一台機器上運行。這也是系統設計的起點。

想像一位使用者要訪問你的網站，流程大概是這樣：

![upload_3d5646cee4b84ef9398839ff6dae94a3](https://hackmd.io/_uploads/B1bvxvgxWe.png)

1. 使用者在瀏覽器輸入 `www.example.com`
2. 瀏覽器或手機 App 先去查 **DNS**（Domain Name System）
3. DNS 把網址轉成 **IP 位址**（像是 `93.184.216.34`）
4. 拿到 IP 後，發送 **HTTP 請求**到 Web Server
5. Web Server 去資料庫撈資料，回傳給使用者

**這個流程中出現的角色：**
- **USER**：就是你我，用電腦或手機發請求的人。我在底下有補充[電腦跟手機訪問網站的差別](#1-Web-Application-vs-Mobile-Application)，有興趣可以看
- **IP**：伺服器的地址，就像門牌號碼
- **DB**：存資料的地方，帳號、文章、商品資料都在這
- **DNS**：[底下有補充](#2-DNS%EF%BC%88Domain-Name-System%EF%BC%89)

---

## Database（資料庫）

使用者越來越多，一台伺服器快撐不住了。怎麼辦？

最直接的做法就是把「處理請求」和「存資料」分開。

把 Web/Mobile traffic（web tier）和 Database（data tier）分開後，它們可以各自擴展。流量爆了？加 web server。資料太多？升級資料庫。互不干擾。

### 該選哪種資料庫？

要先決定用 **Relational Database** 還是 **Non-Relational Database**。

可以參考我這篇 [Relational Database vs Non-Relational Database](https://hackmd.io/@Moofon/HyfVei9xWe)

**Relational Database（RDBMS / SQL Database）**

MySQL、PostgreSQL、Oracle 這些。用 table 跟 row 存資料，可以用 SQL 做 join。發展超過 40 年了，很穩。

**Non-Relational Database（NoSQL Database）**

像 MongoDB、Redis、Cassandra、DynamoDB。分成 key-value stores、graph stores、column stores、document stores 四大類。通常不支援 join。

其實對大部分人來說，**關聯式資料庫夠用了**。但如果符合以下情況，可以考慮 NoSQL：

- 需要超低延遲
- 資料沒什麼關聯
- 只是要做序列化跟反序列化（JSON、XML 之類）
- 要存超大量資料

像我最近做的專案，在網路上爬了大量文本來餵給 AI 做 RAG，幾百萬個字。我就選 NoSQL，因為這些文本資料之間沒什麼關聯。如果用關聯式資料庫，應該會有問題。

---

## Vertical Scaling vs Horizontal Scaling

資料量每天都在增長，資料庫遲早撐不住。這時候要擴展。而擴展又分成Vertical Scaling(垂直擴展) 與 Horizontal Scaling(水平擴展)。

![1_gee5Zkih2dZ7tYWRgmRbkw](https://hackmd.io/_uploads/r1aLsoKgWl.png)


### Vertical Scaling（Scale Up）

**簡單說就是換台更猛的機器。**

加 CPU、加 RAM、加硬碟。根據 Amazon RDS，你可以買到有 24 TB RAM 的資料庫伺服器。這種怪獸機器確實能處理大量資料。

像 2013 年的 Stack Overflow 每月有 1000 多萬訪客，但只用一台 master database。

但 vertical scaling 有幾個問題：

- **硬體有極限**。不可能無限加 CPU 跟 RAM
- **單點故障**。這台掛了，整個系統就掛了
- **超貴**。越強的機器越貴，而且不是線性成長

### Horizontal Scaling（Scale Out / Sharding）

**不是換更強的機器，是加更多機器。**

![DB_image_3_cropped](https://hackmd.io/_uploads/BypwhsYgZx.png)


Sharding 就是把大型資料庫切成更小的 shards。每個 shard schema 相同，但存的資料各自獨立。

假設我們用 `price 價格區間` 來分配：

```
0 < price < 49.99 → Shard 0
50 < price < 99.99 → Shard 1
price > 100 → Shard 2
```

每次存取資料時，用 hash function 算出要去哪個 shard。

**Sharding Key 的選擇很重要**。選不好的話，某些 shard 會過載。

流量小的時候，vertical scaling 簡單有效。但對大規模應用來說，**horizontal scaling 是唯一出路**。

現在幾乎都是用水平擴展，除非是小專案。不過 [Sharding](#3-Sharding-%E7%9A%84%E5%95%8F%E9%A1%8C) 也會帶來新問題，最底下有說明。

---

## Load Balancer（負載平衡器）

單一 web server 有兩個致命問題：

1. **Single Point of Failure**：Server 掛了，網站就掛了
2. **無法處理高流量**：流量暴增時，單台 server 會被打爆

Load Balancer 的作用就是把請求平均分配給多台 web servers。

![54114fcc-cce5-4f0d-a678-47f8f0339fd4_1304x1076](https://hackmd.io/_uploads/SySuh2sbWg.jpg)


> 💡 **圖片說明**：使用者(Public IP) → Load Balancer → 分配請求(Private IP)給多台 Web Servers

現在，使用者連到 Load Balancer 的 [Public IP](#4-Public-IP-vs-Private-IP)，而非直接連 web server。Load Balancer 再決定要把請求送給哪台 server。

### 解決單點故障

假設現在有 Server 1 和 Server 2。

- Server 1 掛了 → Load Balancer 自動把所有流量導到 Server 2
- 同時啟動新的 server 補上

使用者完全無感，網站不會中斷。

### 自動擴展

流量爆增時，只要加更多 web servers，Load Balancer 會自動開始分配流量給新 servers。

流量下降時，關掉幾台 server 省成本。這就是 horizontal scaling 的優勢。

之前在實習的時候，半夜 server 突然掛掉，還好有 Load Balancer 自動 failover 到備用 server。不然隔天就準備出事了xd。

---

## Database Replication（資料庫複製）

單一 database 的問題跟單一 web server 一樣：掛了就全毀。

Database Replication 透過 **Master-Slave 架構**來解決。

![Database Replication 架構圖](https://hackmd.io/_uploads/HkZqo6ibWg.png)


> 💡 **圖片說明**：Master DB (寫入) → 自動複製 → 多台 Slave DB (讀取)

- **Master Database**：只負責寫入（insert, delete, update）
- **Slave Database**：只負責讀取（read）

Master 的資料會自動同步到 Slaves。大部分應用讀取遠多於寫入，所以通常會有多台 Slaves。

### 效能提升

寫入集中在 Master，讀取分散到多台 Slaves 並行處理。

由於讀取遠大於寫入。像是大家在電商平台更多時間都是再逛逛，沒有實際在買東西。所以多了專門用來讀取的slave db後，查詢速度會明顯變快很多。

### 可靠性與高可用性

資料被複製到多個地方。某台 database server 硬碟壞掉、被天災毀掉，至少資料還有備份。

而且任一台 database 掛了，系統還能繼續運作，至於要如何處理掛掉的db，在底下有[補充說明](#5-DB-Failover-%E8%99%95%E7%90%86)。

---

### 現在的架構

![完整架構](https://hackmd.io/_uploads/Byiw6Ts-Zl.png)

> 💡 **圖片說明**：DNS → Load Balancer → Web Servers → Master/Slave DBs

完整流程：
1. 使用者從 DNS 拿到 Load Balancer 的 IP
2. Load Balancer 把請求分配給某台 Web Server
3. Web Server 從 Slave Database 讀取資料
4. 寫入、修改、刪除操作會送到 Master Database
5. Master 自動同步資料到 Slaves

### 還不夠快

這一篇我們完成了：

* ✅ 系統與資料庫概覽
* ✅ Load Balancer 分散流量
* ✅ Database Replication 避免單點故障
* ✅ Private IP 保護內部 servers

**雖然系統穩定了，但載入速度還不夠快！下一篇會聊如何用 Cache 和 CDN 來優化載入速度。**

---

## 補充說明

### 1. Web Application vs Mobile Application

伺服器的流量主要來自兩邊：**Web Application** 跟 **Mobile Application**。

**Web Application**

Web App 通常後端用 Java、Python 處理邏輯跟資料，前端用 HTML、CSS、JavaScript 顯示內容。

**Mobile Application**

Mobile App 透過 **HTTP 協定**跟伺服器溝通，常用 **JSON 格式**傳資料，因為輕量又好讀。

舉例，當 App 發請求：
```
GET /users/12
```

伺服器回傳使用者資料：
```json
{
  "id": 12,
  "name": "Moofon",
  "role": "Goblin"
}
```

這就是最基本的 API 請求。

---

### 2. DNS（Domain Name System）

DNS 就像網路世界的電話簿，把 `www.example.com` 這種人類看得懂的網址，轉成機器看得懂的 IP 位址（像 `93.184.216.34`）。

流程：
- 使用者輸入網址
- DNS 查對應的 IP
- 回傳給瀏覽器

💡 就像你要去一家餐廳（www.example.com），DNS 就是 Google Maps 告訴你地址在哪（93.184.216.34）。

---

### 3. Sharding 的問題

Sharding 很強，但也有麻煩的地方：

**Resharding data（重新分片）**

當某個 shard 資料增長太快，要重新分配資料、改 sharding function。這過程很煩，系統可能還要暫時停機。

解決方法是用 Consistent Hashing（一致性雜湊），後面章節會講。

**Celebrity problem（Hotspot key problem）**

名人問題。想想我的 IG 粉絲跟 NBA 球星差多少？如果 Instagram 用 Sharding，把 LeBron、Curry、KD 都放同一個 shard，那個 shard 會因為請求太多爆掉。

解決方法是給熱門資料獨立的 shard。

**Join 和 De-normalization**

資料庫被 shard 後，跨 shard 的 join 會超慢。

比如 User 在 Shard 3，Order 散在其他 shards，要組合起來很麻煩。

**解決方法：De-normalization**

就是把資料重複存。Order 表格不只存 user_id，連 user 的名字、email 都直接存進去。查詢時就不用跨 shard join 了。

缺點是資料重複佔空間，更新時要改多個地方。但這就是 sharding 的取捨：**用空間換速度**。

---

### 4. Public IP vs Private IP

是電資出身的人一定對這個不陌生，IP 是網路最重要的概念。而IP又分成～

- **Public IP**：Load Balancer 對外的 IP，使用者連這個
- **Private IP**：Web servers 之間溝通用的內部 IP

所以 Load Balancer 的設計有個重要細節：

Web servers 只有 Private IP，外網連不到。駭客只能攻擊 Load Balancer 這層，打不進後面的 servers。

其實與你家裡的 Wifi 路由器的概念很類似，**不過是反過來的！**：

![Private-vs-Public_2-1024x455](https://hackmd.io/_uploads/Hyce1aiZ-e.png)

路由器有對外的 Public IP（中華電信給的），而手機、電腦都是內部的 Private IP（192.168.x.x）。

當你上網時：電腦透過內部 IP 連到路由器 → 路由器用 Public IP 對外溝通 → 外面的人只看得到路由器，看不到你家裡的裝置。

---

### 5. DB Failover 處理

**Slave 掛了**

流量會自動導到其他健康的 Slaves，同時啟動新的 Slave 來替換。

**Master 掛了**

某台 Slave 會被提升為新的 Master，接手寫入工作。但這比較複雜，因為 Slave 的資料可能還沒完全同步，需要跑 data recovery scripts 來補齊。

---

## 參考資料
1. https://medium.com/@arumugamperumal471/scaling-from-one-to-million-single-server-setup-33998e5adadc
2. System Design Interview – An Insider's Guide by Alex Xu
3. https://miro.medium.com/1*gee5Zkih2dZ7tYWRgmRbkw.png
4. https://assets.digitalocean.com/articles/understanding_sharding/DB_image_3_cropped.png
5. https://substackcdn.com/image/fetch/$s_!jpjg!,w_1200,h_600,c_fill,f_jpg,q_auto:good,fl_progressive:steep,g_auto/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54114fcc-cce5-4f0d-a678-47f8f0339fd4_1304x1076.png