🎯 什麼情境該想到我
當你「想讓多個應用程式即時共享同一份資料、避免資料在系統間複製與延遲」的時候,考慮讓它們讀寫同一個資料庫。
⚙️ 怎麼用(步驟 / 公式)
意圖:讓多個應用程式把資料存進同一個共享資料庫,透過共同的資料模型來整合。
做法 / 結構要點:
- 各應用直接讀寫同一個資料庫,資料即時可見、由 DB 的交易機制保證一致性。
- 需要一個各方都同意的統一 schema。
- 沒有資料搬運或格式轉換問題,因為大家看的是同一份資料。
★★ 這個模式今天的名聲兩極,而兩邊都對
微服務社群:「共享資料庫是頭號反模式」 ← 針對「跨服務邊界共用」
務實派: 「單體用共享資料庫完全正確」 ← 針對「同一個界限內共用」
★ 判準不是「幾個應用」,是「這些應用是不是同一個 bounded context」。
同一個界限內(同一個團隊、同一組不變式、一起部署)→ 共享資料庫是最簡單也最正確的選擇。
跨界限(不同團隊、不同發布節奏)→ schema 變成一份沒人擁有的公共契約(見 內幕交易)。
★ 具體會怎麼壞:四個真實情境
-- ① ★ 沒人敢改欄位
ALTER TABLE orders DROP COLUMN legacy_status;
-- 「誰在用這一欄?」→ 沒人知道,因為有六個服務直接 SELECT *
-- ② ★ 一個服務的慢查詢拖垮所有人
SELECT * FROM orders WHERE JSON_EXTRACT(meta,'$.tag') = 'x'; -- 全表掃描
-- → 連線池被吃光,其他服務全部 timeout(見 [[工具-服務容錯設計]])
-- ③ ★ 鎖競爭與死鎖
-- A 服務先鎖 orders 再鎖 users;B 服務反過來 → 死鎖
-- 而且你在 A 的程式碼裡看不到 B 的存在
-- ④ ★★ 沒有人能回答「這個欄位的不變式是什麼」
-- orders.status 只能從 pending → paid,但六個服務各自寫入,
-- 於是一定有一個會寫出 pending → shipped★ 第 ④ 點是最根本的:不變式必須由單一擁有者強制。
共享資料庫把「誰負責保證資料正確」這個問題變成無主的。
★ 中間路線(比「全部拆開」務實)
| 做法 | 說明 |
|---|---|
| ★ 一張表只有一個寫入者 | 其他人可以讀,但只能透過 view/唯讀帳號。寫入權就是所有權 |
| ★ schema per service,同一個 DB 實例 | 共用基礎設施(省成本)但不共用 schema。之後要拆很容易 |
| ★ 唯讀副本給報表用 | 分析查詢打副本,不影響線上(見 工具-資料複製) |
| ★★ CDC:把共享資料庫變成事件來源 | Debezium 讀 WAL/binlog → 發成 Kafka 事件。下游從「直接讀表」變成「訂閱事件」 |
★ CDC 是遷移路徑上最實用的一招:
現況:service B 直接 SELECT orders
步驟一:Debezium 監聽 orders 的 WAL,發成 orders.changed 事件
步驟二:service B 改成訂閱事件、維護自己的讀模型
步驟三:撤掉 service B 對 orders 表的權限
→ ★ 每一步都可回退,而且不需要改 service A
(WAL 為什麼能當可靠的變更來源,見 工具-預寫日誌與崩潰復原。)
★ 什麼時候共享資料庫就是對的答案
- ★ 單體應用(或模組化單體)——本來就是一個部署單元。
- ★ 需要跨實體的交易與強一致:「扣庫存 + 建訂單」要原子。
跨服務要做到這件事,代價是 Saga/補償交易(見 工具-分散式事務的取捨)——貴得多。 - ★ 兩個服務其實該是一個。判準:它們是否總是一起改、一起發布?
- 讀多寫少的參考資料(國別碼、幣別表)——共用一份唯讀資料沒有壞處。
- 報表/BI——直接查(副本)比建一條資料管線便宜。
🧪 我實際套用的紀錄
- (待填)
⚠️ 注意 / 什麼時候不適用
-
高耦合:共用的 schema 變成所有應用的公共契約,難以獨立演進,改一個欄位可能牽動全部。
-
效能與鎖競爭:多方同時讀寫同一庫可能造成瓶頸與死鎖。
-
難以整合外部或既有系統(它們各有自己的資料庫),且單一資料庫是共同的單點風險。
-
★★ 判準是「是不是同一個 bounded context」,不是「幾個應用」。 單體用共享資料庫是對的。
-
★ 寫入權就是所有權。一張表只讓一個服務寫,是最便宜也最有效的邊界。
-
★ 跨服務共用 schema = 一份沒人擁有的公共契約,改一個欄位要協調所有人(見 內幕交易)。
-
★ 不變式必須由單一擁有者強制。六個服務各自寫
status,一定有一個會寫錯。 -
★ 一個服務的慢查詢會吃掉共用連線池,拖垮所有人。
-
拆分前先做 CDC(Debezium 讀 WAL)。它讓遷移可以一步一步、每步可回退。
-
跨服務強一致的代價是 Saga,比共享資料庫貴得多。先確認你真的需要拆。
-
不要為了「微服務」而拆。判準是團隊邊界與發布節奏,不是架構時尚。
🔗 相關工具
- 檔案傳輸 File Transfer(同為整合風格,改用檔案交換、耦合較鬆但延遲較高)
- 遠端程序呼叫 Remote Procedure Invocation(同為整合風格,改用行為介面而非直接共用資料)
- 訊息傳遞 Messaging(同為整合風格,改用非同步訊息降低耦合)
- 企業整合模式
- 檔案傳輸、遠端程序呼叫、訊息傳遞 —— 另外三種整合風格
- 內幕交易 —— 共享 schema 就是這個壞味道
- 工具-資料複製 —— 唯讀副本
- 工具-預寫日誌與崩潰復原 —— CDC 的基礎
- 工具-分散式事務的取捨 —— 拆開之後的代價
- 工具-服務邊界與演進式拆分 —— 切在哪、怎麼切