微服務到底是什麼:跟模組化的差別,跟該不該拆的判斷
模組化是同一個 process 裡怎麼切,微服務是要不要拆成不同 process——這兩個常被搞混。從三個判斷標準到 Netflix、Segment、Amazon Prime Video 三個業界案例,整理「到底該不該拆」這件事。
上篇,講概念。中間動手前的環境準備寫在〈Docker Compose 入門筆記〉,實際拆了什麼寫在下篇〈用 moon-bbq-backend 練習拆微服務〉。
一、先分清楚:模組化 vs 微服務
這兩個常被搞混,但差別很明確:模組化是「同一個 process 裡怎麼切」,微服務是「要不要拆成不同的 process」。
模組化(Modularization)
在同一個可執行檔、同一個 process裡,把程式碼依照責任切成清楚的模組/套件,模組之間用函式呼叫溝通。
例如把某段邏輯搬進一個新的 package,裡面包成一個乾淨的函式,呼叫方直接呼叫它——這就是模組化。特徵:
- 還是一份 build、一個 process、一次 deploy
- 呼叫是編譯期檢查的:函式簽章對不上,編譯就會失敗,不會有「兩邊悄悄失聯」這種事
- 可以共用同一個資料庫交易(transaction),要嘛一起成功要嘛一起失敗
- 幾乎沒有額外代價,單純是把一坨程式碼整理乾淨
微服務(Microservices)
拆成多個獨立的 process,各自可以獨立部署、獨立重啟、獨立擴容,彼此跨網路溝通(HTTP、gRPC、訊息佇列、Pub/Sub 都算)。
特徵:
- 多份 build、多個 process、各自 deploy
- 呼叫沒有編譯期檢查——合約(頻道名稱、API 格式)打錯字,程式照樣編譯成功、照樣部署成功,只是兩邊永遠對不上話,這種錯誤只能等執行期才發現
- 沒辦法共用交易,任何一邊掛掉都要處理「另一邊不知道發生什麼事」的情況,所以要挑「能容忍失敗」的功能來拆
- 換來的是真正的獨立部署/獨立擴容/故障隔離,但這些好處要在有實際規模壓力時才划算
一句話記憶:先問「這段程式碼亂不亂」,亂就模組化就好,幾乎沒有代價;只有在真的需要「獨立部署/獨立擴容/故障隔離」的時候,才值得付微服務的代價。
二、怎麼判斷一段程式碼「適合」拆成微服務(不是模組化,是真的拆process)
拆之前先問自己三個問題:
1. 這件事跟核心功能是不是同一個「責任」?
如果拆出去的服務做的事情概念上完全不同(例如「誰坐在哪」vs「記錄有多少人來過」),就是好的邊界。如果只是把同一個責任硬切兩半,拆了只會多一層網路呼叫,沒有實質好處,純粹增加複雜度。
2. 它能不能容忍「非同步」或「暫時性失敗」?
這是最關鍵的判斷標準。如果這個服務掛掉幾秒鐘,使用者體驗會不會壞掉?
- 能容忍 → 好的候選,因為微服務最大的代價就是「網路會斷、會慢」,要挑那些扛得住這件事的功能來拆。
- 不能容忍(需要強一致性、低延遲)→ 通常該留在同一個服務裡,除非你有很好的理由(擴容、團隊邊界)去承擔拆分的代價。
3. 它現在是不是「順便」擠在關鍵路徑裡,卻其實不需要立即完成?
如果一段程式碼現在同步跑在使用者體驗的熱路徑上,但邏輯上其實可以晚點做、或做失敗也沒差,那它常常是「不小心長在錯誤地方」的功能——拆出去反而讓主服務變快、變簡單,是最容易發現、也最容易帶來立即好處的一類候選。
三、業界案例:什麼時候真的該拆、什麼時候是拆過頭
拆對了:Netflix(2008–2016)
2008 年 Netflix 發生一次資料庫損毀,DVD 出貨停擺三天——問題根源是整個系統是一個跑在 Oracle 上的單體 Java 應用,單點故障能拖垮整間公司。這次事故加上串流業務即將爆炸性成長(訂閱數之後從 940 萬衝到近 9000 萬,API 請求量從約 2000 萬衝到每天 20 億+),逼得他們花了 7 年時間把服務一個一個拆出去搬上 AWS,直到 2016 年最後拆掉的帳務系統才算完成。過程中每個痛點都逼出一個對應工具:service discovery 的缺口逼出 Eureka、串聯故障逼出斷路器 Hystrix、邊緣路由需求逼出 Zuul。
這是真正有組織/規模壓力逼出來的拆分:不是為了拆而拆,是舊架構真的撐不住了,而且是漸進式的(新舊架構並行跑了好幾年),不是一次重寫。
拆過頭:Segment「Goodbye Microservices」(2018)
Segment 早期把一個核心功能拆成 140 多個微服務(每個客戶整合都各自一個服務)。這其實是把一個模組化程度的差異(不同客戶整合的邏輯不同),錯當成需要獨立部署/擴容的微服務問題來解——結果不是變快,是團隊被複雜度淹沒,部署、測試、維運全部指數級變麻煩。後來他們把這 140 多個服務合併回一個服務(重新做好模組化,而不是微服務化),結果團隊生產力(功能改進量)反而提升 46%,但也承認因此犧牲了一些故障隔離跟記憶體內快取的效率。這篇文章後來變成業界很常被引用的反面教材。
連 Amazon 自己都走回頭路:Prime Video(2023)
最有意思的是這個——Amazon 是最早推微服務/SOA 那批公司,結果他們自己的 Prime Video 影片品質監控團隊,把原本用 Step Functions + Lambda 拆得很細的架構,合併回一個 process,成本直接降 90%。原因是拆太細之後,服務間搬資料、orchestration 本身的開銷比實際運算還貴。要注意這不是「Amazon 放棄微服務」的新聞,是一個團隊發現自己那個特定工作負載不適合拆這麼細,公司其他地方該用微服務的照樣在用。
三個案例的共同結論
Netflix 是「有真實壓力逼你拆」;Segment 跟 Prime Video 是「拆的顆粒度/理由跟實際負載對不上,合回去反而更好」,而且 Segment 那個案例根本就是模組化跟微服務搞混的活教材。拆分要有真實驅動力(規模、故障隔離、團隊邊界),不是預設選項——多數程式碼亂的問題,答案是模組化,不是微服務。
Sources:
- Netflix: From Monolith to Microservices — A 7-Year Architecture Evolution
- Goodbye Microservices: From 100s of problem children to 1 superstar(Twilio Segment)
- Reduce costs by 90% by moving from microservices to monolith: Amazon internal case study
四、一句話總結
拆微服務不是「把程式碼搬家」,是先確認這是個「該不該多開一個 process」的問題(而不是單純程式碼亂該模組化),再找出「容忍失敗、責任獨立、不該擠在熱路徑」的那一小塊,設計好它跟主服務之間的合約(事件或 API),最後才談部署。核心的、需要強一致性的熱路徑反而是最不該拆的部分。下篇會把這套判斷實際套用在 moon-bbq-backend 上,包含拆完之後老實檢討「這次拆分到底有沒有帶來實質好處」。