「系統設計沒有唯一正確答案,只有在特定約束條件下更好或更差的取捨。 一個能說清楚『我選這個方案是因為 X,代價是 Y,但在這個規模下可以接受』的工程師, 比背答案的人值錢十倍。」
— 大型系統設計面試核心原則
為什麼系統設計「感覺很難」?
系統設計難不在於技術本身,而在於它沒有固定答案。 演算法題有正確解,系統設計題是在模糊需求下做取捨。 初學者最常犯的錯誤有三個:
直接跳進實作細節
「我會用 Redis 做快取,然後加一個 message queue,然後...」——等等,我們連用戶量是多少都不知道,為什麼先設計快取?
把系統設計當技術名詞清單
把所有聽過的技術全丟進去:Kafka、Redis、ElasticSearch、CDN...但說不清楚為什麼用這個,而不是更簡單的方案。
忽略約束條件(Constraints)
每個系統都有它的脈絡:預算、團隊規模、維護成本、延遲要求。「最好的架構」是在這些約束下最合適的,不是技術上最酷的。
正確的思考順序
Step 1:需求釐清(Requirements Clarification)
永遠是第一步,花 5 分鐘在這裡,能省 30 分鐘的冤枉路
面試官說「設計 URL Shortener」,這個描述至少有十種不同的系統。 在設計之前,你需要問到兩類需求:
功能性需求(Functional)
系統「要做什麼」
用戶能縮短 URL?
能自訂短網址後綴?
短網址有過期時間嗎?
需要點擊次數統計嗎?
需要使用者帳號系統嗎?
非功能性需求(Non-Functional)
系統「要多好」
讀寫比例是多少?(read-heavy?)
延遲要求?(p99 < 100ms?)
可用性要求?(99.9%? 99.99%?)
一致性 vs 可用性如何取捨?
資料需要持久化多久?
📝 範例:URL Shortener 的需求確認結果
Step 2:容量估算(Capacity Estimation)
「大概」的數字比沒有數字好,數量級對了就夠了
估算的目的不是精確,而是判斷架構規模: 一台機器夠不夠?需不需要分片?需不需要快取? 先記住幾個常用數字:
實戰估算:URL Shortener(100M DAU)
📊 QPS(每秒請求數)
💾 儲存空間
🔑 短碼需求
Step 3:高層架構設計(High-Level Design)
先畫方塊圖,再說每個方塊的職責
估算結果是架構的「輸入」,不是終點。 12K QPS 告訴你需要快取;36TB 告訴你需要分片——這些數字現在要轉換成具體的元件與資料流。 高層架構設計的原則是:先確認誰負責什麼,再討論怎麼做。
URL Shortener 高層架構
distribute traffic
縮短 URL
redirect
點擊統計
hot URLs, TTL
URL 對照表
ClickHouse / BigQuery
注意這個架構把讀寫分離成兩個服務(Write Service / Read Service)。 這是因為我們算出讀取是 12K QPS,但寫入只有 115 QPS——兩者規模差一百倍, 分開設計讓各自可以獨立擴縮(Scale Out)。
Step 4:深入關鍵模組
面試官通常會指定一個模組讓你深入
以 URL Shortener 為例,最值得深入的是「短碼生成策略」。 這看起來簡單,但真正做到不重複、高可用,有幾種思路:
方案 A:雜湊截斷(MD5 / SHA-256)
✅ 優點
• 實作簡單
• 相同 URL 產生相同短碼(去重)
❌ 缺點
• Hash 碰撞需處理
• 難以支援自訂後綴
方案 B:全局自增 ID(Auto-increment)
✅ 優點
• 唯一性保證
• 可 Base62 encode 成短碼
❌ 缺點
• 單點瓶頸(DB 序列)
• 可預測的 ID(安全疑慮)
方案 C:分散式 ID(Snowflake / UUID)
✅ 優點
• 無單點瓶頸
• 分散式環境安全產生
❌ 缺點
• UUID 太長(需截斷)
• Snowflake 需時鐘同步
📌 Ticket Server 是什麼?
Ticket Server 是解決「分散式環境下全局唯一自增 ID」的輕量方案。 做法是:有一台專用的 DB,只做一件事——維護一個 counter 並批量發放 ID 段。 每個服務啟動時或用完本地 ID 池後,向 Ticket Server 請求一批 ID(例如 1000 個), 之後在本地順序使用,不需要每次生成 ID 都打 DB。 這樣 Ticket Server 的 QPS 壓力降為實際生成 QPS / 批次大小(1000),同時 ID 保持有序(對 B-Tree 索引友好)。
🎯 面試建議答法
「我選方案 B(自增 ID + Base62)搭配 Ticket Server 解決單點問題: 用一台專用的 Ticket DB 批量發放 ID 段(例如每次領取 1000 個), 服務在本地消化這 1000 個 ID 再去領下一批。 這樣 Ticket Server 的壓力降為 QPS / 1000,且服務有本地 ID 池不依賴 DB 每次請求。」
通用系統設計框架(可套用任何題目)
釐清需求
5 min功能性需求(做什麼)+非功能性需求(多快、多穩、多大)
容量估算
5 min估算 QPS、儲存量、頻寬。數量級對了就夠,不要糾結精確數字
高層架構
10 min畫方塊圖,確認主要元件、資料流、讀寫路徑
深入關鍵模組
15 min根據面試官指引,深入一個或兩個最複雜的子問題
識別瓶頸與優化
5 minSPOF(單點故障)、熱點(hot key)、跨區延遲、一致性問題
必知的系統設計取捨
| 取捨維度 | 選 A | 選 B | 何時選 A? |
|---|---|---|---|
| 一致性 vs 可用性 | 強一致(CP) | 最終一致(AP) | 金融交易、庫存扣減 |
| 讀延遲 vs 寫延遲 | Read-through Cache | Write-through Cache | 讀多寫少(>10:1) |
| SQL vs NoSQL | SQL(關聯式) | NoSQL(文件/KV) | 結構化、需要 JOIN、ACID |
| 垂直擴展 vs 水平擴展 | Scale Up(更大機器) | Scale Out(更多機器) | 初期簡單,有上限 |
| 同步 vs 非同步 | 同步處理 | 非同步 Queue | 非核心路徑、可延遲處理 |
重點整理
先問需求再動手
功能性 + 非功能性需求確認清楚,才能判斷架構方向。跳過這步是最常見的失誤。
估算決定架構
12K QPS → 需要快取;36TB → 需要分片。數字是架構決策的依據,不是裝飾。
先廣後深
先畫方塊圖(30 分鐘內),再由面試官指引深入特定模組。別一開始就死在細節裡。
說清楚取捨
每個決策都要說「我選 X 而不是 Y,是因為在我們的場景下 Z 更重要」。沒有取捨的設計是沒想清楚的設計。
下一篇
EP.02 負載均衡