從單體架構轉向微服務會改變你對資料的思考方式。這不僅僅是程式碼重構的過程,更是一種根本性的轉變,涉及資訊在系統中如何流動、儲存與相互關聯。對於初級工程師而言,這種轉變常會帶來特定的挑戰,尤其是在建模資料關係時。在分散式環境中複製單體架構中熟悉模式的直覺很強,但卻極具危險性。
實體關係圖(ERD)是資料層的藍圖。在微服務架構中,設計不良的ERD可能導致緊密耦合、資料不一致,以及難以後續解決的運營噩夢。本指南探討早期資料建模中常見的關鍵陷阱,並提供一套結構化的方法來避免這些問題。我們將探討共用架構、關係處理與領域邊界,不依賴特定工具,而是專注於架構原則。

💡 單體架構的遺留陷阱
大多數工程師在職業生涯初期都從單體應用開始。在這種環境中,單一資料庫通常為多個模組服務。實體關係圖反映了這種現實,呈現出一個龐大的表格網絡,並以外鍵將所有內容連接起來。當初級工程師接觸微服務時,自然傾向於繪製出類似於過去工作成果的放大版ER圖。
這種方法之所以失敗,是因為微服務是圍繞業務能力設計的,而非技術實現細節。單體架構的ERD著重於整個系統的寫入一致性與事務完整性。而微服務的ERD則必須著重於服務隔離與獨立部署。當你繪製一個將整個系統視為單一資料庫的圖表時,即使你意圖部署分散式服務,其實也隱含地在為單體架構設計。
- 單體架構思維:假設所有資料都有一個唯一的真實來源。
- 微服務思維:接受由特定服務管理的多個真實來源。
- ERD範圍:應按服務範圍劃分,而非整個組織。
第一個錯誤是繪製全域ERD。相反地,每個服務都應擁有自己的架構設計。圖表應反映特定服務的內部狀態,而非應用程式的整體狀態。這種區別對於維持使微服務可行的獨立性至關重要。
🗄️ 錯誤一:共用資料庫反模式
最常見的錯誤之一是假設服務應共用資料庫架構。在圖表中,這表現為兩個不同的服務讀取並寫入同一組表格。雖然這看似能有效存取資料,但卻會產生隱藏的依賴關係。
如果服務A與服務B都存取相同的資料庫表格,它們就會緊密耦合。若服務A需要更改欄位名稱以支援新功能,服務B將會失效。這迫使兩者必須同時部署以維持相容性。這完全違背了微服務的核心目的——獨立部署與擴展。
為何這種做法會失敗
- 部署耦合:架構變更需要跨團隊協調。
- 失敗傳播:一個服務中的架構遷移問題會影響其他服務。
- 安全風險:對表格的廣泛存取會增加資料外洩的風險面。
在ER圖中,這通常表現為表格標籤包含多個服務名稱,或外鍵指向由其他服務擁有的表格。正確的做法是確保每個服務獨佔其資料。資料共享應透過API呼叫或非同步事件進行,而非直接資料庫存取。
正確做法的視覺化呈現
審查圖表時,應關注表格的所有權。每個表格都應屬於單一服務。若兩服務之間需要建立關係,應以參考或事件觸發方式建模,而非外鍵約束。
🔗 錯誤二:將外鍵視為全域真實
外鍵是維持單一資料庫內資料完整性的強大工具。在分散式系統中,跨服務邊界強制執行外鍵約束在技術上極為複雜,且往往得不償失。初級工程師經常試圖使用跨越不同服務資料庫的外鍵來建模關係。
試圖在兩個獨立資料庫之間強制執行外鍵關係,需要使用分散式交易。這會引入延遲與複雜性。若服務A的資料庫無法使用,服務B的完整性檢查將失敗。這可能導致整個架構中出現連鎖式失敗。
一致性權衡
在微服務中,你經常必須在強一致性與可用性之間做出選擇。外鍵強制實現強一致性。在分散式環境中,跨服務維持強一致性成本高昂。這會減慢寫入操作,並增加系統停機的風險。
- 強一致性: 確保資料在所有節點上立即相同。在分散式系統中很難實現。
- 最終一致性: 接受資料在收斂前可能短暫不同。微服務中更為首選。
取代外鍵,使用邏輯引用。儲存相關實體的 ID,但在資料庫層級不強制關係。驗證應在應用程式層級進行,或透過事件驗證。這讓服務能夠獨立演進,無需等待其他服務驗證資料完整性。
🌍 錯誤 3:在資料庫設計中忽略領域邊界
資料模型應遵循業務領域,而非技術基礎架構。此概念是領域驅動設計(DDD)的核心。常見錯誤是根據技術便利性而非業務能力來分組資料。例如,建立一個由計費服務與驗證服務共用的「使用者」資料表。
當實體關係圖反映出技術便利性高於業務邊界時,會導致高度耦合。計費服務可能需要使用者的付款紀錄,而驗證服務僅需憑證。將這些合併成單一的「使用者」實體,會造成臃腫的資料結構,難以維護。
識別有界上下文
為避免此問題,應定義資料使用的上下文。每個服務應代表一個特定的有界上下文。實體關係圖應反映該特定上下文的術語與結構。
- 驗證上下文: 關注身分、憑證與會話。
- 訂購上下文: 關注產品、價格與配送狀態。
- 通知上下文: 關注通訊管道、訊息與配送紀錄。
若你在圖中看到一個被五個不同服務引用的資料表,應質疑其位置。它很可能屬於共用程式庫,或應拆分成多個服務專用的實體。若資料服務於不同上下文,應予以複製,而非因應不同技術需求而共享。
🔄 錯誤 4:過度優化連接操作
在傳統資料庫設計中,規範化是減少冗餘的關鍵。工程師致力於第三範式,以確保資料能有效儲存。在微服務中,這種思維可能導致過度規範化。若某服務需要另一服務中的資料,便容易產生設計一個能跨網路高效連接的資料結構的誘惑。
跨服務的連接操作成本高昂。它需要網路呼叫、序列化與聚合。若實體關係圖設計為促進這些連接,系統將變得脆弱。網路延遲會成為瓶頸,系統也喪失獨立擴展的能力。
去規範化策略
通常更佳的做法是在服務內進行去規範化。若服務 A 需要服務 B 的資料,服務 A 應維護必要欄位的副本。這稱為讀取模型。服務 A 的實體關係圖應反映此去規範化結構。
- 寫入模型: 優化於更新與嚴格完整性(通常為規範化)。
- 讀取模型: 優化於查詢與效能(通常為去規範化)。
建立圖表時,應問:「這個關係是否需要連接才能回答業務問題?」若答案是肯定的,應考慮在需要資料的服務內複製資料。這能降低延遲,並消除對其他服務資料庫可用性的依賴。
📈 錯誤 5:忽略資料的演進與版本控制
資料結構會隨時間改變。服務也會演進。在初始的實體關係圖中,常見的疏忽是缺乏資料結構遷移的計畫。資深工程師常為當前需求設計完美的資料結構,卻未考慮六個月後會如何變化。
在單體架構中,你可以一次性部署就刪除欄位並更新應用程式。在微服務中,若要刪除被外部 API 或其他服務使用的欄位,則需要謹慎的棄用策略。ERD 不僅應顯示目前的狀態,還應暗示版本控制策略。
處理資料結構變更
考慮你的資料結構如何處理新增欄位。不要直接新增欄位,可考慮使用彈性資料類型或獨立的元資料表格。這樣可以在不破壞現有使用者的情況下引入新的屬性。
- 向後相容性: 新增欄位對現有客戶端應為選擇性。
- 棄用: 舊有欄位應在圖表的註解中標示為將被移除。
- 版本控制: API 版本通常決定資料結構版本。
在圖表中記錄欄位的生命周期,有助於未來工程師理解變更何時引入以及何時可能被移除。這可防止「資料結構漂移」,即不同服務對相同資料有不同的解讀。
📊 比較:單體架構 vs. 微服務資料模式
| 功能 | 單體架構方法 | 微服務方法 |
|---|---|---|
| 資料擁有權 | 集中於單一資料庫 | 依服務分散管理 |
| 關聯性 | 外部索引鍵 | API 呼叫或事件 |
| 一致性 | 強一致性(ACID) | 最終一致性(CAP 定理) |
| 資料結構變更 | 單一部署 | 獨立部署 |
| 連接運算 | 資料庫連接 | 應用程式聚合 |
| 失敗範圍 | 單點故障 | 服務故障隔離 |
✅ 初級工程師驗證清單
在最終確定您的實體關係圖之前,請逐一核對此清單,以確保您已避開常見的架構陷阱。
- 所有權:每個資料表是否都屬於單一服務?
- 依賴關係:是否有任何外鍵指向服務以外的資料表?
- 範圍:此圖是否代表一個有界上下文,而非整個系統?
- 讀取模型:讀取優化結構是否與寫入模型分離?
- 事件:資料變更是否以事件形式建模,以便其他服務使用?
- 冪等性:資料更新是否可以安全重試而不會重複?
- 隱私:敏感欄位是否在設計中分離或加密?
🛠️ 實際實施步驟
開始繪製圖表時,請遵循以下步驟以維持架構完整性。
- 定義上下文:首先列出該服務所支援的業務功能。
- 識別實體:列出與這些功能相關的名詞(例如:訂單、客戶、發票)。
- 確定關係:繪製這些實體之間的互動方式。避免跨服務連結。
- 選擇資料類型:選擇支援所需操作的類型(例如:JSON 用於靈活資料,字串用於識別碼)。
- 檢視耦合度:檢查是否有任何實體需要來自其他服務的資料才能正確運作。
- 記錄約束條件: 記錄一致性檢查發生的位置(例如,API 層與資料庫層之間)。
🔒 安全與合規性考量
資料模型設計也涉及安全問題。一個常見的錯誤是假設資料庫安全就足夠了。在分散式系統中,資料會在服務之間流動。ERD 應反映敏感資料存放的位置。
如果某個服務儲存個人識別資訊(PII),圖表應特別標示此點。存取控制必須圍繞服務邊界設計。如果你設計的資料結構將 PII 分散在不同服務的多個資料表中,則難以確保合規性。應將敏感資料限制在負責管理該類資料的服務內部。
🧠 數據架構的最終思考
為微服務設計 ER 圖表需要改變思維方式。這不是要連接盡可能多的點,而是要將點分離,使其能夠獨立移動。圖表是團隊溝通的工具,應清楚顯示資料存放的位置、擁有者以及資料流動的方式。
避免試圖以集中化的方式讓圖表看起來完美。接受分散式資料的混亂性。接受資料複製有時是為了性能與隔離而必要的。透過專注於領域邊界與服務所有權,你將建立一個支持長期成長與穩定性的基礎。
請記住,目標不僅是儲存資料,更是要支援組織的業務能力。當圖表反映的是業務邏輯而非資料庫機制時,它就會成為整個工程團隊的寶貴資產。持續專注於隔離、清晰度,以及在不破壞系統的前提下持續演進的能力。
定期審查你的圖表。隨著系統成長,模式可能會改變。第一個服務有效的做法,未必適用於第十個服務。持續優化資料模型,可確保你的架構保持穩健,並與技術目標保持一致。保持警覺,避免陷入單體系統的模式,你將打造出具韌性且可擴展的系統。












