跳至主要内容

30 篇文章 含有標籤「系統設計」

從需求拆解到架構設計、擴展與維運

檢視所有標籤

系統設計系列文10:Media Pipeline 上傳一張圖片,中間發生了什麼事?

· 閱讀時間約 5 分鐘
阿昇
Software Engineer

昨天把 CDN 接上了 PokeThreads,圖片跟影片不再經過 Application Server,直接由 CDN 搭配 Object Storage 提供服務:

CDN 搭配 Object Storage 提供媒體服務的架構圖(沿用 Day 9 的架構圖)

但這裡其實跳過了一個環節:

Pikachu 上傳一張 20MB 的原始照片,到這張照片變成 CDN 上那張輕巧的圖片之間,中間到底發生了什麼事?

總不可能不處理 20MB 的原始檔案,直接拿去讓全世界的人下載吧。

系統設計系列文8:Cache 讓你不用每次都要讀 Database

· 閱讀時間約 6 分鐘
阿昇
Software Engineer

目前 PokeThreads 的架構已經有多台 Server 和 Primary / Replica Database:

目前已具備多台 Server 與 Primary / Replica Database 的架構圖(沿用 Day 7 的架構圖)

Read 壓力被 Replica 分攤掉了,但仔細想想

這些 Read 真的每一次都需要重新查詢 Database 嗎?

假設現在有 100 萬個使用者,很多人一打開 PokeThreads 第一件事就是看 Feed。回想 Day 3 的內容,光是組出一份 Feed,後端就要做:

找到 Following
↓
找到 Posts
↓
排序
↓
Pagination

如果每一次 Request 都重新跑一次這整套流程:

Request 1 → Database
Request 2 → Database
Request 3 → Database
Request 4 → Database
...

代表大量 Request 其實都在請 Database 重複做很類似的事情。

但有些資料根本不需要每次都重新算,例如:

  • User Profile
  • Post 內容
  • 組好的 Feed
  • 某些 Counter
  • 某些熱門資料

這些資料在一段時間內,可能會被大量使用者反覆讀取。那能不能把這些常用資料,暫時放在一個更適合大量讀取的地方?

這就是 Cache(快取)要解決的問題。

系統設計系列文7:一顆 Database 不夠用:Database Replication

· 閱讀時間約 9 分鐘
阿昇
Software Engineer

前幾天把 Application Server 從一台變成多台,也把 Session 從 Server Memory 搬到共用的 Session Store:

瀏覽器 -> Load Balancer -> Server(多台,Stateless)-> Database

你可注意到了:Server 變多了,Database 卻還是只有一台。

不管前面有幾台 Server 在分攤流量,最後所有的讀寫都會匯聚到同一個 Database。

Application Layer 雖然順利做到了 Horizontal Scaling,Database 反而變成了新的瓶頸。

這也是大型系統很常出現的現象:解決了一個瓶頸,下一層往往會冒出新的瓶頸。

系統設計系列文6:Session 要放哪?

· 閱讀時間約 6 分鐘
阿昇
Software Engineer

昨天我們把 Application Server 從一台擴展成多台,靠 Load Balancer 分攤流量:

Load Balancer 放在 Client 與 Application Server 之間的架構圖(沿用 Day 5 的架構圖)

這解決了單台 Server 的容量問題,但當時刻意跳過了一個細節:

如果同一個使用者的 Request,被分配到不同的 Server,這些 Server 還認得出他是誰嗎?

回想 Day 2,我們是把 Session 直接存在 Server 的 Memory 裡:

Server
├── Application
└── Session(存在 Memory 裡)
├── Pikachu
├── Charmander
└── Squirtle

這種把使用者狀態保存在 Server 本機的做法,稱為 Stateful Server。在只有一台 Server 的時候完全沒問題,但現在情況不一樣了。

系統設計系列文5:一台 Server 不夠用:Vertical Scaling vs Horizontal Scaling

· 閱讀時間約 5 分鐘
阿昇
Software Engineer

這幾天我們把最陽春的 PokeThreads 做出來了,也解決了 Feed 該回傳什麼內容的問題,但整個架構其實還停留在最原始的狀態:

瀏覽器 -> Server -> Database

只有一台 Server,所有使用者的 Request 都打到同一個地方。當時的假設是使用者只有 100 人,這台 Server 綽綽有餘,但如果使用者從 100 人變成 10 萬人、100 萬人呢?

即使 Database 還撐得住,這一台 Server 本身的運算能力終究有極限,於是我們要面對一個很基本、卻也很重要的問題:

當一台 Server 不夠用了,我們該怎麼辦?

系統設計系列文4:REST vs GraphQL:前後端到底該怎麼聊天?

· 閱讀時間約 5 分鐘
阿昇
Software Engineer

昨天把 Feed 的核心邏輯做出來了,GET /feed 已經能正確回傳 Pikachu 追蹤的人發的貼文,但那時候刻意跳過了一個問題:這支 API 到底該回傳什麼形狀的資料?

目前的做法很直覺,後端把 Post 撈出來,整包塞進 JSON 回傳:

{
"posts": [
{
"id": 101,
"author_id": 42,
"content": "Hello PokeThreads",
"created_at": "2026-01-01T00:00:00Z"
}
],
"next_cursor": "abc123"
}

這種「一個資源、一個固定形狀」的 API 設計方式,就是 REST(Representational State Transfer)。

今天想討論的是:RESTful API 會在哪裡開始卡住?

系統設計系列文2:設計最簡單的社群網站

· 閱讀時間約 5 分鐘
阿昇
Software Engineer

上一篇估算出來的流量其實非常小,每秒寫入大概 1~2 次、讀取大概 100 多次,這種規模不需要任何花俏的架構,先做出一個 「堪用」 的版本就好。

這也是這個系列一路會遵守的原則:

不要一開始就把系統蓋大,而是先用最簡單的方式解決問題,避免過度工程(Over-engineering)。