iT邦幫忙

2025 iThome 鐵人賽

DAY 15
0
Software Development

微服務導入:從觀念到落地的架構實戰地圖系列 第 15

微服務導入 – Day 15 微服務中的跨資料庫查詢

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20250922/20178262ci7uVjjam0.png

在上一篇我們談過 Shared Database 與 Database per Service 的設計。結論是:在微服務架構中,Database per Service 雖然帶來了自治性與彈性,但也同時打破了傳統「跨表 Join」的便利。

換句話說,原本只要一條 SQL 就能完成的查詢,現在可能需要跨越多個微服務、甚至多種資料庫,這對開發與系統設計帶來了新的挑戰。(我今年好像一直在這個循環裡面繞 …)

今天,我們就來探討兩個常見的解決模式:

  • API Composition —— 以 API 為單位組合查詢結果
  • CQRS (Command Query Responsibility Segregation) —— 用專門的讀庫支援跨服務查詢

問題背景:跨服務查詢的難題

假設我們有一個線上商店系統,它包含下列微服務:

  • Customer Service:管理客戶資訊(信用額度、基本資料)
  • Order Service:管理訂單資訊(訂單清單、消費金額)
  • Product Service:管理商品目錄與庫存

當前端要顯示「客戶詳細資訊」時,通常需要以下資料:

  • 客戶的基本資料(Customer Service)
  • 客戶的訂單歷史(Order Service)
  • 訂單中商品的詳細資訊(Product Service)

在傳統單體式應用中,我們只要寫一個 SQL Join:

SELECT c.customer_id, c.name, o.order_id, p.product_name, p.price
FROM customer c
JOIN orders o ON c.customer_id = o.customer_id
JOIN products p ON o.product_id = p.product_id
WHERE c.customer_id = 123;

但在微服務架構中,資料分散在三個不同服務、三個不同資料庫,這樣的 SQL 查詢不再可能。

API Composition 模式

API Composition 是一種 透過 API 組合不同微服務的查詢結果 的設計模式。
它的角色分成兩類:

  • API 組合器(API Composer):通常是 API Gateway 或 BFF (Backend for Frontend),負責統一發送請求並組合結果。
  • 服務提供者(Service Provider):各個微服務本身,提供查詢 API。

以「客戶詳細資訊查詢」為例:

  1. API Gateway 收到前端請求 /customer/123/details
  2. API Gateway 依序呼叫:
    2.1. Customer Service → GET /customers/123
    2.2. Order Service → GET /customers/123/orders
    2.3. Product Service → GET /products/{id}
  3. API Gateway 將三個服務的回應組合成一個 JSON,回傳給前端。

結果可能是這樣:

{
  "customer": {
    "id": 123,
    "name": "Alice",
    "creditLimit": 5000
  },
  "orders": [
    {
      "orderId": 1001,
      "total": 200,
      "items": [
        { "productName": "iPhone 15", "price": 150 },
        { "productName": "Phone Case", "price": 50 }
      ]
    }
  ]
}

API Composition 的優點

  • 簡單直觀:不需額外維護讀庫或事件系統,開發門檻低。
  • 即時性:每次查詢都取得最新資料,無需考慮同步延遲。
  • 靈活性:可快速組合多個服務資料,適合中小型查詢。

API Composition 的限制與缺點

  • 效能問題:需要多次網路呼叫,若一個頁面需要查 5 個服務,可能會很慢。
  • 可用性風險:只要一個服務失效,整個查詢就失敗。
  • 缺乏交易一致性:不同服務的資料可能不是同一個時間點的狀態 (隱含著 Saga Pattern 必須被實作)。

整理上述的內容,可以歸納在「查詢資料筆數少」、「即時性比一致性更重要」的情境可採用此模式。


CQRS 模式

CQRS(Command Query Responsibility Segregation,指令與查詢責任分離)是一種 將「寫」與「讀」分離 的設計模式。

  • Command(寫):由各微服務負責,資料進入專屬的資料庫。
  • Query(讀):由專門的「查詢庫」處理,該查詢庫會透過 事件(Event) 來保持更新。

一樣以「客戶詳細資訊查詢」為例:

  1. Customer Service、Order Service、Product Service 各自維護自己的資料庫。
  2. 當資料變動時(新增訂單、修改商品),它們會發布 Domain Event:
    2.1. CustomerUpdated
    2.2. OrderCreated
    2.3. ProductUpdated
  3. 一個專門的 Query Service(或查詢資料庫)訂閱這些事件,並將資料存到一個「查詢資料庫」(通常是 NoSQL,如 MongoDB、ElasticSearch)。
  4. 當前端需要查詢「客戶詳細資訊」時,直接查詢 Query DB,而不是打到多個微服務。

優點:

  • 高效能:跨服務查詢只需打一次資料庫,不用多次 API 呼叫。
  • 可擴展性:可以針對查詢需求設計專門的讀庫,例如 ElasticSearch 支援全文檢索。
  • 靈活報表:適合需要跨大量資料的查詢或 BI 報表。

缺點

  • 資料同步延遲:事件傳遞有時間差,查詢資料可能不是最新的。
  • 架構複雜度高:需要事件機制(Kafka, RabbitMQ),並維護額外的查詢庫。
  • 開發成本高:需要設計額外的資料同步與一致性處理。

整理上述的內容,可以歸納在「報表系統」、「BI 分析」、「批次程式」採用這個模式。


API Composition vs CQRS

維度 API Composition CQRS
查詢方式 由 API Gateway/BFF 發送多次請求,組合結果 由查詢庫(Read DB)一次查詢
即時性 最新資料 可能有延遲(最終一致性)
效能 跨多服務呼叫,延遲較高 高效能,查詢一次即可
適用場景 小量資料、即時性高 報表、大量查詢、跨服務數據整合
複雜度 簡單 複雜(需事件驅動架構)
一致性 無交易一致性保證 最終一致性

結語

在微服務架構下,跨資料庫查詢 是一個必然的挑戰。

  • API Composition:適合簡單、少量的查詢需求,即時但效能有限。
  • CQRS:適合大量、複雜的查詢,效能強大,但需要付出同步延遲與架構複雜度的代價。

一個成熟的微服務架構,往往 兩者並用:

  • 前台查詢 → API Composition
  • 後台報表 → CQRS

最終,選擇的關鍵在於 需求優先順序:是要即時,還是要高效能?


上一篇
微服務導入 – Day 14 微服務架構下的資料庫設計
系列文
微服務導入:從觀念到落地的架構實戰地圖15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言