大家都說微服務比較現代,你是不是也在猶豫要不要拆?這篇帶你用一個問題決定:你有幾個要獨立出貨的團隊?
我讀到一則匿名網路貼文,裡面說了一個故事。故事沒辦法核實,細節可能被誇大,我把它當成一則寓言來讀。
貼文是這樣說的:技術長要求重構十年前的核心系統,唯一的條件是「不能有單點故障」。團隊花半年把一支程式拆成 47 個服務,導入 Kafka、Kubernetes、Redis、整套監控,資料庫、快取、訊息佇列全部做成叢集,架構文件寫了兩百多頁。上線五分鐘後,整個系統掛了。每個 Pod 都是 Healthy,每台資料庫都正常,原因是有人改 DNS 時多打了一個字元,服務們找不到彼此。
一年後,他們連 DNS 都做了高可用。然後唯一懂整套架構的資深工程師離職了。文件在 GitLab,GitLab 登入要靠 Authentication Service,Authentication Service 的部署方式寫在 GitLab。
真假先不論,裡面每一步都太合理了,合理到我相信很多團隊正走在同一條路上。
快速回答 先數你有幾個要獨立出貨的團隊,再決定要幾個服務。預設選模組化單體:程式碼留在同一個部署單位,按業務領域切模組。有兩個以上團隊要用不同節奏上線,或某一塊的負載、故障模式明顯不同,而且邊界在單體裡畫得出來、扛得起分散式營運,才只拆那一塊。拆得開的是程式碼,拆不開的是依賴;AI 讓拆服務變便宜,也讓理解系統變貴。Twilio Segment 拆到 140 多個服務後,最後收回成一個。
盲目拆微服務不會消滅單點故障,只是把單點搬到 DNS、登入與少數人腦中
回頭看故事裡的決定,沒有一個是蠢的。服務互相呼叫耦合太高,所以導入事件驅動;部署太麻煩,所以上 Kubernetes;查詢太慢,所以加快取;出錯找不到原因,所以補可觀測性。每個決定都解掉一個看得見的問題。
問題出在每個解法都帶進一個新的依賴。快取帶進「哪一份資料才是真的」,事件帶進「這筆訂單的 Correlation ID 是多少」,Kubernetes 帶進 Pod 排不上去的那個早上。單點故障沒有被消滅,它從架構圖上看得見的地方,搬到了沒人畫的地方:DNS、登入系統、一個人的腦袋。
現實裡發生過幾乎一樣的事。2021 年 10 月 4 日,Facebook、Instagram、WhatsApp 全球斷線約七小時。Meta 事後的說明寫得很直白:DNS 全面失效,弄壞了平常用來調查和修復事故的內部工具,工程師只好親自跑到資料中心現場重啟系統。修東西的工具,依賴著壞掉的那個東西。
拆得開的是程式碼,拆不開的是依賴。
微服務買到團隊獨立上線,代價是網路延遲、資料一致性與維運溢價
我不反對微服務。它解決的問題是真的:一個團隊改訂單,不必等另一個團隊改會員才能上線;影音轉檔吃滿 CPU,不必連帶擴充整個網站;一個模組出錯,不至於拖垮全部。
日本二手交易平台 Mercari 從 2018 年起把 PHP 單體遷到 Go 微服務,他們寫得很清楚,動機是組織要長大:每個團隊從設計到維運對自己的服務負責,系統鬆耦合,少依賴其他團隊。這是一個為了讓很多人能同時工作而付的價錢。
這個價錢有名字。Martin Fowler 叫它 Microservice Premium(微服務溢價):服務之間的網路呼叫、分散的資料一致性、追蹤、部署管線、on-call,全部要有人扛。系統夠複雜、團隊夠多,這筆溢價划算;系統不夠複雜,溢價只會拖慢團隊。他在 2015 年的觀察到今天還成立:成功的微服務故事,幾乎都是從一個長太大的單體拆出來的;一開始就做成微服務的系統,幾乎都陷入麻煩。
Twilio Segment 是很好的反例。他們為了隔離故障,替每個資料目的地各開一個服務和佇列,最後長到 140 多個。結果三位全職工程師把大部分時間花在讓系統活著,開發速度掉下來,錯誤率衝上去。後來他們把這些服務收回成一個,2018 年寫成〈Goodbye Microservices〉:共用函式庫的改進,一年從 32 項增加到 46 項。他們也誠實寫下代價:故障隔離變難了,一個 bug 可能拖垮整個服務。
兩個方向都有人付錢。差別在於你付的那筆,換到的東西你用不用得上。
單體架構省成本的前提是畫出模組邊界,否則只會長成大泥球
單體的好處很樸素:一次部署、同一個行程裡的函式呼叫、一個資料庫交易、出事時只有一個地方要查。這是單體最被低估的能力。
2023 年,Amazon Prime Video 的監控團隊發過一篇文章(原文已下架,以下依 DevClass 的報導),說他們把一個原本由 Step Functions 和 Lambda 串起來的影音品質檢測服務,收成單一行程,基礎設施成本降了九成。這篇文章被很多人拿來宣布「微服務已死」。Sam Newman 的提醒比較冷靜:這篇講的主要是函式計價和長駐機器的價差,適用範圍很窄。我同意他。這個案例說明的是「這一個服務切太碎了」,它沒有說 Amazon 該變回一個單體。
單體的條件是邊界。Shopify 是世界上最大的 Ruby on Rails 程式庫之一,超過一千位工程師在同一份程式碼上工作了十多年。他們評估過微服務,最後選了模組化單體(Modular Monolith):程式碼留在同一個部署單位,按訂單、出貨、庫存、帳務這類業務領域切模組,再用工具強制模組之間的邊界。用他們的話說,要的是更高的模組化,部署單位的數量不增加。
邊界畫不出來的單體,叫大泥球(Big Ball of Mud,沒有清楚結構、什麼都互相牽動的程式)。把大泥球拆成服務,只會得到一個分散在網路上的大泥球。Mercari 也坦白:面向使用者的功能拆得順利,最複雜、依賴最深的核心交易邏輯,因為領域分析不夠,到他們 2021 年寫那篇回顧時,程式和資料仍然纏在一起。
把這四家放在一起看,方向各不相同,買到的東西卻都對得上當時的問題:
- 單體拆成微服務
- 團隊變多,要各自負責、各自上線
- 核心交易邏輯沒拆開
- 140 多個服務收回成一個
- 三個人整天在維持系統
- 故障隔離變難
- 一個服務從函式收成單一行程
- 函式計價太貴(據報導)
- 只適用這一個服務
- 留在模組化單體
- 一千多人在同一份程式碼上工作
- 邊界要靠工具強制
沒有一家是因為「微服務比較現代」或「單體比較簡單」而做決定。他們都先說得出自己的問題,再挑架構。
AI 讓拆服務變便宜,卻讓跨儲存庫理解與除錯成本暴增
這一節是我的判斷,也是我寫這篇真正想說的事。
2026 年,叫 Agent 生成 47 個服務的骨架、Dockerfile、Kubernetes YAML、Helm chart,大概一個下午就有了。故事裡團隊花好幾個月做的拆分,現在的工具讓它便宜到幾乎不用想。
便宜的是產出,貴的是之後的每一天。每多一個服務,就多一條網路依賴、一份要對齊的資料、一組要有人看的告警。Agent 可以替你寫出排程設定,它不會替你在凌晨三點判斷三個副本為什麼都排不上去。
CNCF 2025 年的年度調查也指向同一個方向。使用容器的組織裡,82% 已經在正式環境跑 Kubernetes,工具幾乎普及了;受訪者回報的最大挑戰,換成「開發團隊的文化改變」(47%),訓練不足(36%)和複雜度(34%)排在後面。把東西架起來已經不難,卡住團隊的越來越是人和理解。
還有一件常被忽略的事:Agent 讀程式的方式。在一個模組化單體裡,Agent 可以從一個函式一路追到資料庫,呼叫鏈都在同一個 repo。拆成 47 個服務之後,服務之間怎麼呼叫、傳什麼格式,活在網路上、活在別的 repo、活在某個人的記憶裡。人看不到全貌,Agent 也看不到。
那個故事的結局,指向的就是這個。整套系統最後的單點故障,是知識只存在一個人身上。AI 讓寫程式的人變多、寫得更快,這個單點只會更危險,除非你把系統怎麼運作寫進 repo,讓下一個人和下一個 Agent 都讀得到。
架構決策四問:先確認團隊獨立性與負載差異,再評估維運與邊界
我自己的預設是模組化單體。四個問題分成兩組:前兩題問「要不要拆」,後兩題問「能不能拆」。
要不要拆
- 有沒有兩個以上的團隊,需要用不同節奏獨立上線?只有一個團隊,拆服務多半只是把同一群人的協調,從程式碼搬到網路上。
- 有沒有哪一塊的負載或故障模式,和其他部分明顯不同?例如影音轉檔、批次報表,它們需要獨立擴充,或不能拖垮主站。
兩題都答「否」,就留在模組化單體,把力氣花在模組邊界上。
能不能拆
- 你們扛得起分散式的營運成本嗎?追蹤、on-call、資料一致性、跨服務的測試,要有人和預算。
- 這條邊界,在單體裡畫得出來嗎?邊界在程式碼裡站得住,拆出去才有意義。
需要拆、也拆得動,才只把那一塊拆出去,而且拆出去的服務要有一個叫得出名字的負責團隊。需要拆、卻拆不動,先做領域分析、補營運能力,這段時間仍然留在模組化單體。
這張圖裡最容易憑感覺回答的,是 Q1 和 Q4。「我們有好幾個團隊」「訂單和會員的邊界很清楚」,在會議上說起來都很順,但 git 紀錄會老實告訴你答案:每個模組是哪些人在改,哪幾個模組總是在同一個 commit 裡一起被改。
十分鐘 Git 紀錄檢查:統計模組共同修改頻率,驗證邊界是否真實存在
下面這支 Python 不需要安裝任何套件,在 repo 根目錄執行就好。它想驗證兩件事:一、你說的「團隊」,在程式碼上是不是真的各改各的;二、你想拆開的兩個模組,平常是不是各自改得動。跑出來的結果如果和你的直覺不同,該調整的是直覺。
第一段讀出最近六個月、不含 merge 的 commit,每個 commit 記下作者 email 和改到的檔案。
import subprocess
from collections import Counter
from itertools import combinations
DEPTH = 2 # 模組 = 路徑前兩層,例如 src/orders;依你的目錄結構調整
log = subprocess.run(
["git", "log", "--since=6 months ago", "--no-merges", "--name-only", "--format=%x1e%ae"],
capture_output=True, text=True, check=True).stdout
第二段把每個 commit 拆成「誰改的」和「動到哪些模組」,再數兩件事:每個模組被多少人改過,以及每一對模組在同一個 commit 裡一起被改的次數。
commits = [] # (作者, 這個 commit 動到的模組)
for block in log.split("\x1e")[1:]:
author, *files = block.strip().splitlines()
mods = {"/".join(f.split("/")[:DEPTH]) for f in files if "/" in f}
if mods:
commits.append((author, mods))
touched, together = Counter(), Counter()
authors = {}
for author, mods in commits:
for m in mods:
touched[m] += 1
authors.setdefault(m, set()).add(author)
for a, b in combinations(sorted(mods), 2):
together[(a, b)] += 1
第三段印出結果。「一起改的比例」用比較小的那個模組當分母:小模組的改動有多少比例會牽動另一個。
print("module, commits, authors")
for m, n in touched.most_common(10):
print(f"{m}, {n}, {len(authors[m])}")
print("\npair, changed together, share of the smaller module's commits")
for (a, b), n in together.most_common(10):
print(f"{a} + {b}, {n}, {n / min(touched[a], touched[b]):.0%}")
讀結果的方法很簡單,沒有標準門檻,看的是相對高低:
- 第一張表的 authors 欄,是 Q1 的線索。如果每個模組都是同一批人在改,你們在程式碼上其實是一個團隊,拆服務不會讓誰變得更獨立。
- 第二張表是 Q4 的線索。你想拆開的那一對模組,如果一起改的比例明顯高於其他組合,代表這條邊界在程式碼裡還沒站住。這時候拆出去,每次改動都會變成兩個服務、兩條部署線一起動。
- 這是近似值。一個 commit 同時改兩個模組,不一定代表它們互相依賴;作者 email 也只能粗略代表團隊。它的用處是讓會議上的討論,從「我覺得」變成「這半年的紀錄是這樣」。
iThome 2019 年報導 Kubernetes Summit 時,訪問了曾在 Best Buy 擔任電商架構總監 13 年的 Kevin Matheny(當時是 Gartner 資深研究總監)。他再三強調「微服務架構不應該是企業的目標」,建議企業別先問怎麼擁抱微服務,先問自己有什麼問題需要靠微服務解決。七年過去,這個提醒沒有過時,只是現在多了一個會幫你拆的 AI,讓人更容易跳過這個問題。
結論:先數你有幾個獨立出貨的團隊,再決定拆幾個服務
讀完那篇貼文,我最在意的是那份兩百多頁的架構文件。每一個看得見的單點都被消滅了,看不見的那幾個,從頭到尾沒有寫進去。
架構圖上消失的單點,通常搬進了沒人畫的地方。選單體或選微服務之前,先把那些地方畫出來:DNS、登入、部署腳本、文件放在哪、那個唯一懂全部的人。畫完再回頭看,我猜多數團隊會發現,真正需要獨立出去的只有一兩塊。
先數你有幾個要獨立出貨的團隊,再決定你要幾個服務。
如果你的系統正在交給 Agent 接手,下一步可以讀〈AGENTS.md 怎麼寫?規則寫越多,Agent 反而越貴?(2026 完整教學+範例)〉,把系統怎麼運作寫進 repo。
常見問題
什麼是模組化單體(Modular Monolith)?
程式碼留在同一個部署單位,按訂單、出貨、庫存、帳務這類業務領域切模組,再用工具強制模組之間的邊界。Shopify 有超過一千位工程師在同一份 Ruby on Rails 程式碼上工作,評估過微服務後選了這條路:要更高的模組化,部署單位的數量不增加。
什麼時候該拆微服務?
先問要不要拆:有沒有兩個以上的團隊要用不同節奏獨立上線,有沒有哪一塊的負載或故障模式和其他部分明顯不同。任一題是,再問能不能拆:扛不扛得起追蹤、值班(on-call)、資料一致性這些營運成本,這條邊界在單體裡畫不畫得出來。兩關都過,才只拆那一塊,並交給一個叫得出名字的團隊負責。
Amazon Prime Video 改回單體,代表微服務過時了嗎?
不能這樣推。2023 年 Prime Video 把一個由 Step Functions 和 Lambda 串起來的影音品質檢測服務,收成單一行程,基礎設施成本降了九成(原文已下架,依 DevClass 報導)。Sam Newman 提醒,這主要是函式計價和長駐機器的價差,適用範圍很窄:它說明的是這一個服務切太碎了。
怎麼知道模組邊界夠不夠清楚、能不能拆?
看最近六個月的 git 紀錄:每個模組被多少人改過,哪幾對模組常在同一個 commit 裡一起被改。想拆開的那一對,一起改的比例明顯高於其他組合,可能代表邊界還沒站住,拆出去後常得兩個服務、兩條部署線一起動。這是近似值,用處是讓討論從「我覺得」變成看紀錄。
用 AI 拆微服務變簡單了,還要擔心什麼?
AI 讓拆服務變便宜,讓理解系統變貴。叫 Agent 生成幾十個服務的骨架和 Kubernetes 設定,大概一個下午就有了;之後每多一個服務,就多一條網路依賴、一份要對齊的資料、一組要有人看的告警。服務之間怎麼呼叫,活在網路和別的 repo 裡,人看不到全貌,Agent 也看不到。
延伸閱讀
- 新模型出來了要不要換?AI 功能答錯時,換模型多半沒用(2026 除錯懶人包)
- Multi-Agent Coding 是什麼?同時開很多個 Agent,真的會比較快嗎?(2026 完整解析)
- AI Demo 很成功,為什麼一上線就出事?五條失敗路徑一次看懂(2026)
參考資料
- Martin Fowler (2015-06-03). MonolithFirst;另見 MicroservicePremium.
- Alexandra Noonan, Twilio Segment (2018-07-10). Goodbye Microservices.
- Kirsten Westeinde, Shopify Engineering (2019-02-21). Deconstructing the Monolith: Designing Software that Maximizes Developer Productivity.
- Mercari Engineering (2021-12-13). Microservice Migration at Mercari: The Ideal and the Real.
- Tim Anderson, DevClass (2023-05-05). Reduce costs by 90% by moving from microservices to monolith: Amazon internal case study raises eyebrows(Prime Video 原文已下架,經此報導確認).
- Santosh Janardhan, Meta Engineering (2021-10-05). More details about the October 4 outage.
- CNCF (2026-01-20). Kubernetes established as the de facto operating system for AI as production use hits 82% in 2025 CNCF Annual Cloud Native Survey.
- 王宏仁,iThome (2019-10-02). 擁抱微服務不需一步到位,找對目標比全面重構更重要.
留言0
登入後就能留言。
登入