昨天把 Notification 從 PokeThreads 的 Monolith 拆成了獨立的 Notification Service,跟原本的 API Service 之間用 gRPC 溝通:
API Service ⇄ gRPC ⇄ Notification Service
拆完第一個 Service 之後,接下來這個趨勢大概不會停在這裡。假設之後 Search、Media Processing 也陸續被拆成獨立 Service,Client(瀏覽器、App)要面對的後端,就從「一個 Application」變成「一群 Service」:
如果讓 Client 直接記住每個 Service 的位址、各自打各自的 API,那還沒扯到功能,光是「知道要打誰」這件事,就已經讓前端變得很脆弱。
任何一個 Service 的位址一旦改變,所有 Client 都要跟著改。而且如果每個 Service 都要各自驗證使用者身份,Authentication 邏輯就會重複散落在每個 Service 裡。
這個情境很像逛一間有幾十家專櫃的百貨公司,如果沒有服務台,顧客得自己記住「化妝品在 3 樓左邊第二間、退貨要去 B1」,體驗會很差;有了服務台,顧客只要走到服務台說出需求,服務台自然會引導到正確的專櫃。
這個服務台的角色,放進系統架構裡就是 API Gateway:一個放在 Client 與所有 Backend Service 之間的統一入口。

有了 API Gateway,Client 只需要知道一個 Endpoint,完全不用管背後到底有幾個 Service、各自部署在哪裡。
Gateway 收到 Request 後,依照路徑(例如 /feed、/search)把它轉發到對應的 Service:
Client
↓
API Gateway
↓
┌──────────────┬──────────────┐
↓ ↓ ↓
User Service Feed Service Search Service
這帶來一個額外好處:Backend Service 可以自己升級版本、換位址,例如從 /feed/v1 變成 /feed/v2,只要 Gateway 這一層的路由規則跟著更新,Client 完全感覺不到任何變化。
與其讓 User Service、Feed Service、Search Service 各自重寫一遍「怎麼驗證這個 Token」,不如讓 Gateway 在最外層先攔截、驗證身份,只有合法的 Request 才會被放行到後面的 Service,這樣可以避免同一段安全邏輯在到處複製貼上。
服務台除了引導方向,也常常要顧著現場秩序,這正好是「流量控管」該放的位置。
Gateway 可以在這裡限制單一使用者、單一 IP 每秒可以打多少次 Request,超過就直接擋下,不讓大量 Request 一路衝到 Backend Service。Rate Limiting 的細節留到明天討論。
假設 Client 要打開一個 Profile 頁面,需要同時顯示 User 資料、最近貼文、Follower 數量。沒有 Gateway 的話,Client 得發三次 Request,分別打三個 Service;有了 Gateway,可以提供一支聚合過的 API:
Client
↓
GET /profile/123
↓
API Gateway
├──→ User Service
├──→ Post Service
└──→ Follow Service
↓
合併後的 Response
Client 只需要發一次 Request,剩下的工作交給 Gateway。
因為所有流量都會經過 Gateway,這裡自然也是收集請求量、回應時間、錯誤率這些指標的好地方,替日後要談的 Observability 先打好基礎。
這兩個名詞常被搞混,但層次不一樣。
Load Balancer(Day 5)關心的是「怎麼把 Request 分配到某一群相同的 Server 上」,看的是 IP、連線這類基礎設施層級的資訊;API Gateway 關心的是「這個 Request 該送去哪一個 Service」,看的是 API 路徑、業務邏輯。
實務上兩者經常疊在一起用:
Client -> API Gateway -> [Feed Service 自己的 Load Balancer -> 多台 Feed Server]
Gateway 決定「這是 Feed 的請求」,之後才輪到 Feed Service 自己的 Load Balancer,決定「這次要分給哪一台 Feed Server」。
Load Balancer 是這樣,API Gateway 也是,哪次不是 SPOF?
如果服務台本身倒了,所有客人都進不了任何一家專櫃。所以 API Gateway 本身通常也需要做成一個具備 High Availability 的叢集,而不是單一個節點。
如果把太多業務邏輯(怎麼合併資料、怎麼處理 Partial Failure)都塞進 Gateway,它自己反而會膨脹成一個新的 Monolith。
我們才剛拆開的東西,不應該又在另一層重新長回來。
Request 要多經過 Gateway 這一層轉發,勢必比直接打 Service 多花幾毫秒,這是用「架構彈性」換來的合理代價。
加上 API Gateway 之後,Client 不用再記住一堆 Service 的位址,Authentication、Rate Limiting、Monitoring 這些跨服務都要做的事,也有了一個統一的地方可以集中處理。目前完整的架構長這樣:

不過剛才在 Rate Limiting 那段只是輕輕帶過。
Gateway 到底要怎麼判斷「這個使用者是不是打太快了」?
這是明天要仔細拆解的問題。