← 回所有專案

個人 Side Project ‧ 架構設計與開發 · 2024

電商微服務可觀測性專案

訂單、付款、物流三個微服務組成的電商練習專案,以 DDD 戰略/戰術設計 + Hexagonal Architecture 實作 Event Sourcing,並完整導入 OpenTelemetry 可觀測性堆疊與 Grafana/Tempo MCP 查詢工具。

.NET 8ASP.NET Core Minimal APIDDDEvent SourcingHexagonal ArchitectureWolverineKafka.NET AspireOpenTelemetryGrafanaTempoLokiPrometheusEF Core
電商微服務可觀測性專案

專案概述

一個以訂單(Order)、付款(Payment)、物流(Shipping)三個微服務組成的電商練 習專案,目的不是做出完整電商功能,而是紮實地練習 DDD 戰略與戰術設計、 Event Sourcing 與可觀測性(Observability) 在 .NET 微服務中的落地方 式。每個服務都各自擁有獨立資料庫,並透過領域事件串接彼此的業務流程。

DDD 戰略設計(Strategic Design)

三個服務對應三個獨立的 Bounded Context,各自有自己的資料庫、程式碼庫與通 用語言(Ubiquitous Language),彼此不共用資料表、也不直接呼叫對方的 API:

Bounded Context核心聚合負責的通用語言
OrderServiceOrder建立訂單、確認付款、揀貨、完成訂單、取消訂單
PaymentServicePayment請款、付款完成、付款失敗、取消付款
ShippingServiceShipment請求出貨、已派送、已送達

Context 之間只透過 Kafka 上的領域事件溝通,不共享資料庫、不同步呼叫對 方,屬於以「Published Language(事件即契約)」串接的 Context Mapping: OrderService 發布 OrderCreatedEvent 後即結束自己的職責,完全不知道 PaymentService 內部如何處理請款;PaymentService 處理完也只發布 PaymentCompletedEvent / PaymentFailedEvent,同樣不知道 OrderService 收到後會做什麼。這種鬆耦合讓三個服務可以獨立開發、獨立部署、獨立擴展。

事件流程示意圖

下圖是訂單成立、付款、出貨(以及付款失敗導致取消訂單)的完整事件流:

電商訂單事件流程圖

  • 成功路徑:User → 建立訂單 → OrderCreated → 發起支付請求 → PaymentRequested → 支付完成 → PaymentCompleted → 確認付款 → OrderPaid → 發起配送請求 → ShippingRequested
  • 失敗路徑:支付失敗 → PaymentFailed → 取消訂單 → OrderCancelled

整個流程是典型的事件編舞(Choreography):沒有一個中控服務下指令,每個 服務只是「訂閱自己關心的事件、做完事、發布下一個事件」,服務間的協作關係完全 從事件的訂閱/發布關係中浮現出來。

DDD 戰術設計(Tactical Design)

在單一 Bounded Context 內部,則落實了完整的戰術設計工具箱:

  • Aggregate Root + Event Sourcing:Order、Payment、Shipment 都繼承 共用的 AggregateRoot<TId>。狀態不能被直接賦值修改,只能透過 Apply(DomainEvent) 產生事件、在 When() 中依事件重建狀態,並在 EnsureValidState() 中檢查不變條件(Invariant),修改狀態與驗證規則被綁在 一起,不會有「改了忘記驗證」的問題
    C#
    public void ConfirmPayment()
    {
        Apply(new OrderPaidEvent(Id, ShipmentAddress));
    }
    
    protected override void When(DomainEvent domainEvent)
    {
        switch (domainEvent)
        {
            case OrderCreatedEvent e:
                Status = Status.PendingPayment;
                break;
            case OrderPaidEvent:
                Status = Status.Paid;
                break;
            // ...
        }
    }
    
    protected override void EnsureValidState()
    {
        if (Status == Status.Cancelled && string.IsNullOrEmpty(CancellationReason))
            throw new OrderDomainException("Cancellation reason is required.");
    }
    
  • 強型別 ID(Value Object):OrderId、PaymentId、ShipmentId、 MemberId 都是獨立的 Value Object,而不是裸的 Guid,避免把訂單 ID 誤傳 成會員 ID 這種編譯期抓不到的錯誤
  • 狀態機驅動:Order 從 PendingPayment 開始,依序經過 Paid、 PickingInProgress,最終到達 Completed,或在任何節點被 Cancelled;狀 態轉換完全由事件決定,畫面上看到的狀態永遠是「套用過哪些事件」的結果
  • 事件即事實,而非指令:領域事件一律用過去式命名 (OrderCreatedEvent、PaymentCompletedEvent),代表「已經發生的事 實」,而不是「請你做什麼」的命令,這也是它能安全地被多個服務訂閱、不需要協 調誰先誰後的原因
  • Null Object Pattern:以 INullObject / Order.Null 取代 null 判 斷,减少呼叫端重複的防禦性檢查
  • 事件溯源基礎設施:AggregateRoot 內建 Version、 GetUncommittedEvents()、Load(history),聚合可以完全由事件歷史重建,而 非只依賴目前快照

系統架構

三個服務都採用 Hexagonal Architecture(Ports & Adapters),並拆成獨立的 專案分層:

  • Entities:聚合根與領域事件,對應各服務的狀態機
  • UseCase:應用層服務與 In/Out Port 介面(如 CreateOrderService、 RequestPaymentService、DispatchOrderService)
  • Adapter.Out:以 EF Core 實作的資料庫存取層與 Migration
  • WebApi:Minimal API 端點與事件訂閱者(Event Handler)
  • MainComponent:各服務的組裝根(DI 註冊)

共用套件則抽成獨立專案:E-Commerce.SeedWork(AggregateRoot、DomainEvent 等 DDD 基礎建構)、E-Commerce.EventBus(以 Wolverine 包裝 Kafka 的領域事件匯流 排)、E-Commerce.Diagnostics(Tracing/Metrics/AOP)。並以 .NET Aspire 作為本機開發時的服務編排(AppHost)。

可觀測性亮點

這個專案真正想練習的重點:

  • 以 .NET 內建 ActivitySource 在三個服務中發送 Trace,並將 TraceId 寫入 領域事件本身,讓一筆訂單從建立、付款到出貨的完整流程,能在分散式追蹤中被 串成同一條 Trace
  • 自訂 MethodTracingAttribute(AOP)快速為方法加上追蹤埋點,不需手動包 using activity
  • 透過 IMeterFactory 建立自訂 Metrics(計數器、直方圖、浮動計數器),例如 訂單金額分佈、待處理付款數量
  • 以 OpenTelemetry Collector 統一收集 Trace/Metric/Log,轉送至 Tempo、 Prometheus、Loki,並用 Grafana 儀表板呈現
  • 整合 Grafana MCP 與 Tempo MCP,讓開發時能直接用 TraceQL/PromQL/LogQL 在編輯器內查詢追蹤與指標,不必切換到 Grafana 介面除錯

使用技術

  • 應用層:.NET 8、ASP.NET Core Minimal API、Wolverine、Kafka
  • 架構:Domain-Driven Design(戰略+戰術設計)、Event Sourcing、 Hexagonal Architecture
  • 資料層:EF Core、Code First、MSSQL
  • 可觀測性:OpenTelemetry、Grafana、Tempo、Loki、Prometheus
  • 開發體驗:.NET Aspire、xUnit、Docker Compose

目前狀態

專案仍在持續補充中,目前已完整展示三服務間的事件編舞(Choreography)與可觀測 性串接;後續規劃導入 SAGA Pattern 讓跨服務交易一致性有明確的補償流程可 循,並在服務前加上 API Gateway。