🎯 什麼情境該想到我
當你要決定「一個微服務該多大、邊界畫在哪、從單體怎麼拆」時。
⚙️ 怎麼用
- 按業務能力/限界上下文切(見 工具-限界上下文),不按技術分層切。
- 檢驗好邊界:服務能獨立變更、獨立部署嗎?若一個改動總要同時改好幾個服務 → 邊界錯了。
- 每個服務擁有自己的資料:不共用資料庫,透過 API/事件互動(避免隱性耦合)。
- 服務間別太聊天:若兩服務呼叫極頻繁,可能該合併——高內聚該在同一服務內。
- 演進式拆分:從單體開始,沿著真實痛點與清楚的接縫逐步剝離(見 工具-架構隨業務規模演進)。
📌 這一組三張卡:工具-服務架構的演進與拆分=「有哪些選項」|工具-架構隨業務規模演進=「什麼時候動」|本卡=「切在哪、怎麼切」
★ 檢驗邊界對不對的五個問題
① ★ 能獨立部署嗎?
—— 每次發布都要和別的服務按順序一起上 → ★ 分散式單體,邊界錯了
② ★ 一個典型的功能改動,會動到幾個服務?
—— 常常要改 3 個以上 → 邊界橫切了業務能力
③ ★ 服務之間的呼叫頻率高嗎?
—— 一個請求要來回呼叫 5 次 → ★ 高內聚的東西被切開了,該合併
④ ★ 需要跨服務的交易嗎?
—— 需要 → 聚合被切開了(見 [[工具-分散式事務的取捨]])
⑤ ★ 資料是各自擁有的嗎?
—— 共用同一張表 → 沒有真的拆開,只是兩個程式連同一個 DB
★ 第 ① 題是最實用的單一判準:「能不能只部署這一個?」
★ 絞殺者模式(Strangler Fig):怎麼安全地剝離
① 在單體前面放一層「門面」(proxy / API gateway / 路由層)
Client ──▶ [Facade] ──▶ 單體
② 建新服務,門面把「一小部分流量」導過去(先唯讀、先內部使用者)
Client ──▶ [Facade] ─┬─▶ 單體
└─▶ 新服務 ← ★ 可隨時切回
③ ★ 雙寫 + 對帳:兩邊都寫,比對結果,確認新服務行為一致
④ 逐步提高流量比例,觀察指標
⑤ 舊路徑流量歸零後,★ 觀察一段時間再刪除
★ 關鍵是「每一步都可以立刻回退」。
大爆炸式重寫(big bang rewrite)失敗率極高,因為你在一個無法驗證的狀態下走了幾個月。
★ 最難的部分:拆資料
❌ 兩個服務共用同一個資料庫 → ★ 這不是微服務,是「兩個程式共用一個全域變數」
任一方改 schema 都會弄壞對方,而且沒有編譯器會警告你
拆資料的步驟:
① 先拆「程式碼層」:所有存取都走一個 repository 介面(見 [[工具-接縫]])
② 拆「schema 層」:不同的表分開、拿掉跨表的外鍵與 JOIN
③ ★ 拆「實體層」:真正搬到不同的資料庫
④ 需要對方的資料時 → API 呼叫、事件複製、或 CQRS 讀模型
★ 步驟 ② 通常最痛:JOIN 不見了,要在應用層組合資料。
這也是為什麼「需要頻繁 JOIN 的資料不該被切開」——它是高內聚的訊號。
★ 切錯的三種典型形態
| 錯誤切法 | 症狀 | 正解 |
|---|---|---|
| ★ 按技術分層切 | api-service / logic-service / data-service→ 每個功能都要改三個 | 按業務能力切 |
| ★ 切得太細(奈米服務) | 20 個服務,每個 200 行;一個請求跨 8 個服務 | 合併。服務的大小該由「團隊能負責的範圍」決定 |
| ★ 切在聚合中間 | 需要分散式事務才能維持不變式 | 聚合不可切開(見 工具-實體值物件與聚合) |
★ 服務之間該怎麼通訊
| 方式 | 何時 |
|---|---|
| 同步 HTTP/gRPC | ★ 需要立即的回應、且呼叫鏈短 |
| ★ 非同步事件 | 預設優先考慮:解耦、可重放、天然支援最終一致 |
| 共用資料庫 | ❌ 不要 |
| 檔案/批次 | 大量資料的定期同步 |
★ 同步呼叫會傳遞失敗:A → B → C,C 掛了 A 也掛。
每一層同步呼叫都在降低整體可用性(可用性相乘)。
→ 能非同步就非同步(見 工具-訊息傳遞整合模式)。
★ 拆之前先問:能不能不拆
合併回單體也是一個正當的架構決定。
如果兩個服務總是一起改、一起部署、互相頻繁呼叫——它們本來就是一個東西。
★ 「拆了之後發現不對就合併回去」不是失敗,是正確的演進。
🧪 我實際套用的紀錄
- 2026-07-15:(待填)
⚠️ 注意 / 什麼時候不適用
- ★★ 不要大爆炸重寫。用絞殺者模式,每一步可回退。
- ★ 共用資料庫 = 沒有拆開。這是最常見的假微服務。
- ★ 拆分期間會同時維護兩套,成本更高。要有明確的完成期限與「刪除舊路徑」的任務,
否則會永遠停在中間狀態——那是最糟的狀態。 - 雙寫期間的一致性:兩邊寫入可能不一致 → 一定要有對帳(見 工具-分散式事務的取捨)。
- ★ 邊界會改變。業務變了,昨天對的邊界今天就錯了。保持能再切一次的能力,
而不是追求「一次切對」。 - 拆分的收益要能說清楚。「為了微服務」不是收益;「讓 A 團隊不用等 B 團隊部署」才是。
- 先在單體內劃清邊界(模組化單體)再拆——這樣切錯的成本只是改資料夾。
🔗 相關工具
- 工具-限界上下文 —— 邏輯邊界是拆分的依據
- 工具-服務架構的演進與拆分 —— 各種架構的代價
- 工具-架構隨業務規模演進 —— 什麼時候該動
- 工具-接縫 —— 剝離的第一步:先在程式碼層建立接縫
- 工具-實體值物件與聚合 —— ★ 聚合不可切開
- 工具-分散式事務的取捨 —— 切開之後的代價
- 工具-訊息傳遞整合模式 —— 非同步通訊
- 工具-低風險發布模式 —— 絞殺者的流量切換