
簡介
微服務不僅僅是「拆分整體」。如果分割方式錯誤,您將擁有一個「分散式整體」—同時具有兩種架構的所有缺點。本文介紹了正確劃分微服務的設計原則。
1.什麼是微服務?
微服務是一種架構風格,其中應用程式由許多小型獨立服務組成:
Monolith Microservices
┌──────────────────────┐ ┌──────────┐ ┌──────────┐
│ Một ứng dụng │ │ Order │ │ Payment │
│ ┌──────┐ ┌──────┐ │ │ Service │ │ Service │
│ │Order │ │Payment│ │ → └──────────┘ └──────────┘
│ ├──────┤ ├──────┤ │ ┌──────────┐ ┌──────────┐
│ │Invent│ │Notif │ │ │Inventory │ │ Notif │
│ └──────┘ └──────┘ │ │ Service │ │ Service │
│ Shared Database │ └──────────┘ └──────────┘
└──────────────────────┘ Mỗi service có DB riêng
特點
- 在單獨的進程中運行:每個服務都是一個獨立的進程/容器
- 網路通訊:HTTP/REST、gRPC、訊息佇列
- 獨立部署:部署服務A,不影響服務B
- 私人資料庫:每個服務資料庫模式
- 小團隊:2 個披薩團隊(5-8 人)擁有 1-3 項服務
2.單一職責原則(SRP)
每個服務只負責一項操作並且有一個改變的理由。
✅ Đúng — Mỗi service một nghiệp vụ rõ ràng:
├── OrderService → Quản lý vòng đời đơn hàng
├── PaymentService → Xử lý thanh toán
├── InventoryService → Quản lý tồn kho
├── NotificationService → Gửi email/SMS/push
└── UserService → Quản lý tài khoản
❌ Sai — Service "thùng rác":
├── OrderPaymentService → 2 nghiệp vụ gộp
├── CommonService → Mọi thứ chung
└── UtilityService → Không rõ trách nhiệm
違反 SRP 的跡象
- 服務有 太多不相關的 API 端點
- 更改功能 A 需要重新測試功能 B
- 許多團隊修復相同的服務
- 服務名稱包含“and”或“util”或“common”
3.領域驅動設計(DDD)
3.1 為什麼需要DDD?
DDD 幫助回答了最重要的問題:「每個服務的邊界在哪裡?」
DDD不是依照技術(前端服務、後端服務、資料庫服務)來劃分,而是依照業務領域來劃分。
3.2 策略設計
無所不在的語言
在開發人員和領域專家之間建立通用語言:
Domain Expert (Business): Developer (Tech):
"Đơn hàng" → Order
"Thanh toán" → Payment
"Giao hàng" → Shipment
"Hoàn tiền" → Refund
"Kho hàng" → Inventory
Đảm bảo: Code, API, database, documentation đều dùng cùng thuật ngữ
有界上下文
有界上下文定義了模型具有意義的**範圍:
┌──────────────────────────────────────────────────────┐
│ E-Commerce System │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌──────────────┐ │
│ │ Order │ │ Catalog │ │ Customer │ │
│ │ Context │ │ Context │ │ Context │ │
│ │ │ │ │ │ │ │
│ │ "Product" │ │ "Product" │ │ "Customer" │ │
│ │ = OrderItem │ │ = SKU with │ │ = Account │ │
│ │ (id, qty, │ │ specs, │ │ with prefs, │ │
│ │ price) │ │ images, │ │ addresses │ │
│ │ │ │ pricing │ │ │ │
│ └─────────────┘ └─────────────┘ └──────────────┘ │
│ │
│ Cùng từ "Product" nhưng ý nghĩa KHÁC NHAU │
│ trong mỗi Bounded Context │
└──────────────────────────────────────────────────────┘
重要規則:每個限界上下文 → 一個(或多個)微服務。
3.3 上下文映射-上下文之間的關係
┌─────────────┐ Published ┌──────────────┐
│ Order │────Language────▶│ Payment │
│ Context │ │ Context │
└──────┬──────┘ └──────────────┘
│
│ Customer/Supplier
▼
┌─────────────┐ Conformist ┌──────────────┐
│ Shipping │◀───────────────│ 3rd Party │
│ Context │ │ Logistics │
└─────────────┘ └──────────────┘
| 關係 | 描述 |
|---|---|
| 共享核心 | 2 個上下文共享子集程式碼/模型 |
| 客戶/供應商 | 上游提供API,下游消費 |
| 墨守成規 | 下游完全遵循上游模式 |
| 反腐敗層 | 外部模型與內部模型之間的翻譯層 |
| 發布語言 | 透過標準格式(JSON 模式、Protobuf)進行通訊 |
3.4 戰術設計-建構模組
Bounded Context
│
├── Entity → Có identity, lifecycle (Order, User)
├── Value Object → Không có identity, immutable (Money, Address)
├── Aggregate → Cluster of entities, consistency boundary
│ └── Aggregate Root → Entry point (Order là root, OrderItem là child)
├── Domain Event → Sự kiện nghiệp vụ (OrderCreated, PaymentReceived)
├── Repository → Persistence abstraction
└── Domain Service → Logic không thuộc entity nào (PricingCalculator)
聚合 — 一致性單位
Order Aggregate:
┌───────────────────────────────┐
│ Order (Aggregate Root) │
│ ├── id: "O-001" │
│ ├── status: "confirmed" │
│ ├── total: $500 │
│ │ │
│ ├── OrderItem │
│ │ ├── product: "iPhone" │
│ │ ├── qty: 1 │
│ │ └── price: $400 │
│ │ │
│ ├── OrderItem │
│ │ ├── product: "Case" │
│ │ ├── qty: 1 │
│ │ └── price: $100 │
│ │ │
│ └── ShippingAddress │
│ └── "123 ABC Street" │
└───────────────────────────────┘
Quy tắc:
- Chỉ truy cập thông qua Aggregate Root (Order)
- Một transaction = một aggregate
- Cross-aggregate = eventual consistency
4. 鬆散耦合和高內聚
4.1 鬆散耦合
服務 A 的變更不需要服務 B 的變更。
✅ Loose Coupling:
Order Service ──event──▶ Kafka ──▶ Payment Service
(Thay đổi internal logic của Order → Payment không bị ảnh hưởng)
❌ Tight Coupling:
Order Service ──direct DB query──▶ Payment Database
(Thay đổi schema Payment DB → Order Service bị broken)
4.2 高內聚力
相關功能在一個服務中分組在一起。
✅ High Cohesion:
Payment Service:
├── ProcessPayment()
├── RefundPayment()
├── ValidateCard()
└── GetPaymentHistory()
→ Tất cả đều liên quan đến "thanh toán"
❌ Low Cohesion:
MiscService:
├── ProcessPayment()
├── SendEmail()
├── GenerateReport()
└── ResizeImage()
→ Không liên quan gì đến nhau
5. 什麼時候應該/不應該使用微服務?
5.1 應該在下列情況下使用
- ✅ 大規模系統,許多團隊並行開發
- ✅ 需要獨立擴展系統的每個部分
- ✅ 需要多語言(多種語言/框架)
- ✅ 快速的發布週期,持續部署
- ✅ 複雜的領域,具有清晰的邊界
- ✅ 組織擁有 DevOps 成熟度(CI/CD、監控、容器編排)
5.2 不應在下列情況下使用
- ❌團隊小(< 5人)
- ❌ 簡單應用程序,不太複雜的域
- ❌ 不清楚域邊界
- ❌ 沒有 CI/CD 基礎架構和容器編排
- ❌時間有限發展
- ❌ 團隊沒有操作分散式系統的經驗
5.3 Monolith First
Martin Fowler 建議 「單體優先」:
Phase 1: Monolith
├── Hiểu rõ domain
├── Phát triển nhanh
└── Xác định boundary tự nhiên
Phase 2: Modular Monolith
├── Tách module rõ ràng trong monolith
├── Mỗi module có boundary riêng
└── Giao tiếp qua internal API
Phase 3: Microservices (khi cần)
├── Tách module thành service
├── Thêm API Gateway
└── Event-driven communication
6. 應避免反模式
Distributed Monolith
❌ Chia thành nhiều service nhưng:
- Deploy phải đồng thời tất cả
- Shared database
- Synchronous chain calls dài
- Tightly coupled API contracts
→ Có đầy đủ nhược điểm của cả Monolith VÀ Microservices
→ Không có ưu điểm của cái nào cả
奈米服務(太小)
❌ Chia quá nhỏ:
├── CreateOrderService
├── UpdateOrderService
├── DeleteOrderService
├── GetOrderService
└── ListOrderService
→ Quá nhiều service, overhead network, khó quản lý
→ Nên gom thành: OrderService
7. 總結
| 原理 | 重點 |
|---|---|
| 建議零售價 | 每項服務都有業務、有改變的理由 |
| 國內長途 | 根據Bounded Context,而不是根據技術來劃分服務 |
| 骨材 | 一致性單元,可透過聚合根 |
| 鬆散耦合 | 更改服務 A 不會影響服務 B |
| 高凝聚力 | 相關功能被分組為一項服務 |
| 整體第一 | 開始單體,在理解領域時逐漸分離 |
下一篇文章:同步通訊 - REST API 和 gRPC,微服務之間同步通訊的兩種最受歡迎的協定。