Data Ownership and Distributed Transactions#
資料被拆散後,必須重新組合才能讓系統運作。本章探討如何決定哪個服務擁有哪些資料、如何管理分散式交易,以及如何在缺乏 ACID 保證的環境中達成最終一致性。

Figure 9.1: Once data is broken apart, tables must be assigned to services that own them
Assigning Data Ownership#
- 基本原則:對資料表執行寫入操作的服務就是該表的擁有者
- 此原則在 single ownership 時很簡單,但遇到 joint ownership 或 common ownership 時就變得複雜
Single Ownership Scenario#
- 只有一個服務寫入某張表時,該服務即為表的擁有者
- 資料表成為該服務 bounded context 的一部分
- 其他服務若需讀取此表資料,不可直接存取資料庫,而需透過其他存取模式(見 Chapter 10)
- 建議優先處理 single ownership 情境,先釐清簡單的案例

Figure 9.2: With single ownership, the service that writes to the table becomes the table owner
Common Ownership Scenario#
- 大多數或所有服務都需要寫入同一張表(例如 Audit table)
- 不適合將表放在共享資料庫中,因為會重新引入 change control、connection starvation、fault tolerance 等問題
- 解決方案:指定一個專屬服務作為該表的主要且唯一的擁有者
- 其他需要寫入的服務透過非同步 fire-and-forget messaging 或同步呼叫(REST、gRPC、request-reply messaging)傳送資料給專屬服務
- 例如:建立一個 Audit Service,其他服務透過持久化佇列(persistent queue)以非同步方式送出稽核紀錄

Figure 9.3: Common ownership uses a dedicated service owner
Joint Ownership Scenario#
- 同一 domain 中的少數服務共同寫入同一張表(例如 Catalog Service 與 Inventory Service 共同寫入 Product table)
- 與 common ownership 不同:joint ownership 限於同 domain 內的少數服務
- 有三種主要技術可解決:Table Split、Data Domain、Delegate

Figure 9.4: Joint ownership occurs when multiple services within the same domain perform writes
Table Split Technique#
- 將單一表拆分為多個表,讓每個服務各自擁有自己負責的資料
- 例如:從 Product table 中分離出 Inventory table,Catalog Service 擁有 Product table,Inventory Service 擁有 Inventory table
- 關鍵挑戰:拆分後的表之間需要同步通訊以保持一致性,涉及 availability vs. consistency 的權衡(CAP theorem)

Figure 9.5: Joint ownership can be addressed by breaking apart the shared table
Trade-Offs:
| 優勢 | 劣勢 |
|---|---|
| 保留 bounded context | 表結構必須修改與重構 |
| 單一資料擁有權 | 可能的資料一致性問題 |
| 表更新之間無 ACID 交易 | |
| 資料同步困難 | |
| 表之間可能出現資料重複 |
Data Domain Technique#
- 建立共用的 data domain(shared schema),讓多個服務共享同一組表
- 服務之間形成更寬廣的 bounded context,不再需要跨服務通訊

Figure 9.6: With joint ownership, services can share data by using the data domain technique
- 解決了:服務依賴、效能、可用性、資料一致性問題
- 引入的問題:結構變更需多服務協調、難以控制哪個服務對哪些資料有寫入責任
Trade-Offs:
| 優勢 | 劣勢 |
|---|---|
| 良好的資料存取效能 | 資料結構變更涉及更多服務 |
| 無擴展性與吞吐量問題 | 資料結構變更的測試範圍增加 |
| 資料保持一致 | 資料擁有權治理(寫入責任)困難 |
| 無服務依賴 | 資料結構變更的部署風險增加 |
選擇 data domain technique 時,務必重新評估為何這些服務需要分開。理由可能包括:擴展性差異、容錯需求、程式碼波動性隔離等。
Delegate Technique#
- 將表的 single ownership 指派給一個服務,其他服務透過該服務(delegate)進行更新
- 選擇 delegate 的兩種方式:
- Primary domain priority:將擁有權指派給執行最多 CRUD 操作的服務(通常推薦此方式)

Figure 9.7: Table ownership is assigned to the Catalog service because of domain priority
- Operational characteristics priority:將擁有權指派給需要更高效能、擴展性、可用性的服務

Figure 9.8: Table ownership is assigned to the Inventory Service because of operational characteristics
- 非擁有者服務需透過同步或非同步通訊與 delegate 互動
Trade-Offs:
| 優勢 | 劣勢 |
|---|---|
| 形成 single table ownership | 高度的服務耦合 |
| 良好的資料結構變更控制 | 非擁有者寫入效能較低 |
| 對其他服務抽象化資料結構 | 非擁有者寫入無原子性交易 |
| 非擁有者服務的容錯性較低 |
Service Consolidation Technique#
- 將多個共同擁有表的服務合併為單一服務,消除 joint ownership 問題
- 回歸 single ownership scenario

Figure 9.9: Table ownership is resolved by combining services
Trade-Offs:
| 優勢 | 劣勢 |
|---|---|
| 保留原子性交易 | 更粗粒度的擴展性 |
| 良好的整體效能 | 較低的容錯性 |
| 增加部署風險 | |
| 增加測試範圍 |
Data Ownership Summary#
透過結合以上技術解決不同情境:
- Single ownership(如 Wishlist table):直接指派給寫入的服務
- Common ownership(如 Audit table):建立專屬服務,其他服務透過非同步訊息傳送
- Joint ownership(如 Product table):可選擇 table split、data domain、delegate 或 service consolidation

Figure 9.10: Resulting data ownership using delegate technique for joint ownership
完成 table ownership 指派後,架構師需分析業務工作流及對應的交易需求來驗證指派結果。
Distributed Transactions#
- ACID transaction:atomicity(原子性)、consistency(一致性)、isolation(隔離性)、durability(持久性),確保單一工作單元中的多個資料庫更新全部提交或全部回滾
- 在分散式架構中,當業務請求跨越多個獨立部署的服務時,ACID 交易無法直接適用

Figure 9.11: With ACID transactions, an error on the billing insert causes a rollback

Figure 9.12: Distributed transactions do not support ACID properties
分散式交易不支援 ACID 的原因:
- Atomicity:每個服務各自提交,原子性僅限於單一服務而非整個業務請求
- Consistency:某服務失敗會導致表之間資料不同步;傳統關聯式資料庫約束(如 foreign key)無法跨服務執行
- Isolation:一個服務提交後,資料立即對其他請求可見,即使整個交易尚未完成
- Durability:僅限於各別服務層級,無法保證整個業務交易中所有資料的永久性
分散式交易支援的是 BASE(與 ACID 相對):Basic Availability(基本可用性)、Soft State(軟狀態,交易可能處於未知的進行中狀態)、Eventual Consistency(最終一致性)。
Eventual Consistency Patterns#
分散式架構以最終一致性換取更好的 performance、scalability、elasticity、fault tolerance 與 availability。主要有三種模式:

Figure 9.13: Three separate services are involved in the customer registration process

Figure 9.14: Data is out of sync after the customer unsubscribes from the support plan
Background Synchronization Pattern#
- 使用獨立的外部服務或程序定期檢查資料來源並保持同步(如夜間批次作業或定時排程)
- 適合不需要即時同步的場景

Figure 9.15: The background synchronization pattern uses an external process to ensure data sync

Figure 9.16: The background synchronization pattern is coupled to the data sources
Trade-Offs:
| 優勢 | 劣勢 |
|---|---|
| 服務解耦 | 資料來源耦合 |
| 良好的回應性 | 實作複雜 |
| 破壞 bounded context | |
| 業務邏輯可能重複 | |
| 最終一致性速度慢 |
背景同步程序需要對所有服務的資料表具有寫入權限,等同打破了 bounded context 與 data ownership 的原則。不適用於需要緊密 bounded context 的微服務架構。
Orchestrated Request-Based Pattern#
- 在業務請求處理過程中,透過 orchestrator 同步協調所有資料來源
- Orchestrator 可以是現有服務兼任或獨立的協調服務(建議使用獨立服務)

Figure 9.17: The Customer Profile Service takes on the role of an orchestrator

Figure 9.18: A dedicated orchestration service takes on the role of an orchestrator
- 偏好資料一致性優先於回應性
- 錯誤處理複雜:當部分服務已完成操作但另一服務失敗時,需使用 compensating update(補償性更新)來逆轉已完成的操作

Figure 9.19: Error conditions are very hard to address when using the orchestrated pattern
Trade-Offs:
| 優勢 | 劣勢 |
|---|---|
| 服務解耦 | 回應性較慢 |
| 資料一致性的時效性 | 錯誤處理複雜 |
| 原子性業務請求 | 通常需要補償性交易 |
Event-Based Pattern#
- 使用非同步 publish-and-subscribe(pub/sub)訊息模型,透過 topic 或 event stream 發布事件

Figure 9.20: The event-based pattern uses asynchronous publish-and-subscribe messaging
- 服務監聽特定事件並做出回應
- 最終一致性時間通常很短,因為非同步訊息處理的平行與解耦特性
- 需使用 durable subscribers 確保訊息不遺失
- 錯誤處理:失敗的訊息最終進入 dead letter queue (DLQ),由自動程序或人工處理
Trade-Offs:
| 優勢 | 劣勢 |
|---|---|
| 服務解耦 | 錯誤處理複雜 |
| 資料一致性的時效性 | |
| 快速的回應性 |
Sysops Squad Saga: Data Ownership for Ticket Processing#
團隊將學到的 data ownership 原則應用於 Sysops Squad 系統:
- Single ownership ADR:對資料表執行寫入操作的服務擁有該表,其他服務不得直接存取該資料庫或 schema
- Survey table(joint ownership):Ticket Completion Service 與 Survey Service 都寫入 Survey table。最終決定使用 delegate technique,由 Survey Service 擁有表,Ticket Completion Service 在通知 Survey Service 啟動調查流程時一併傳送所需資料,無需直接存取 Survey table
