microservices-architecture
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMicroservices Architecture
微服务架构
Comprehensive guide for designing and implementing microservices-based systems.
设计和实现基于微服务的系统的综合指南。
Microservices Fundamentals
微服务基础
What are Microservices?
什么是微服务?
MICROSERVICES = Independently deployable services
that do one thing well
Characteristics:
┌─────────────────────────────────────────┐
│ ✓ Single responsibility │
│ ✓ Own their data │
│ ✓ Independently deployable │
│ ✓ Communicate via APIs │
│ ✓ Technology agnostic │
│ ✓ Owned by small teams │
└─────────────────────────────────────────┘MICROSERVICES = Independently deployable services
that do one thing well
Characteristics:
┌─────────────────────────────────────────┐
│ ✓ Single responsibility │
│ ✓ Own their data │
│ ✓ Independently deployable │
│ ✓ Communicate via APIs │
│ ✓ Technology agnostic │
│ ✓ Owned by small teams │
└─────────────────────────────────────────┘Monolith vs Microservices
单体应用 vs 微服务
MONOLITH:
┌─────────────────────────────────────────┐
│ Single Application │
│ ┌──────┬──────┬──────┬──────┐ │
│ │ Users│Orders│ Cart │Search│ │
│ └──────┴──────┴──────┴──────┘ │
│ Single Database │
└─────────────────────────────────────────┘
MICROSERVICES:
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│Users │ │Orders│ │ Cart │ │Search│
│ DB │ │ DB │ │ DB │ │ DB │
└──────┘ └──────┘ └──────┘ └──────┘
│ │ │ │
└─────────┴─────────┴─────────┘
API GatewayMONOLITH:
┌─────────────────────────────────────────┐
│ Single Application │
│ ┌──────┬──────┬──────┬──────┐ │
│ │ Users│Orders│ Cart │Search│ │
│ └──────┴──────┴──────┴──────┘ │
│ Single Database │
└─────────────────────────────────────────┘
MICROSERVICES:
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│Users │ │Orders│ │ Cart │ │Search│
│ DB │ │ DB │ │ DB │ │ DB │
└──────┘ └──────┘ └──────┘ └──────┘
│ │ │ │
└─────────┴─────────┴─────────┘
API GatewayWhen to Use Microservices
何时使用微服务
USE WHEN:
✓ Large, complex domain
✓ Need independent scaling
✓ Multiple teams working in parallel
✓ Different technology needs per service
✓ Fault isolation is critical
✓ Frequent, independent deployments
DON'T USE WHEN:
✗ Small team/application
✗ Simple domain
✗ Tight latency requirements
✗ Limited DevOps maturity
✗ Unclear domain boundariesUSE WHEN:
✓ Large, complex domain
✓ Need independent scaling
✓ Multiple teams working in parallel
✓ Different technology needs per service
✓ Fault isolation is critical
✓ Frequent, independent deployments
DON'T USE WHEN:
✗ Small team/application
✗ Simple domain
✗ Tight latency requirements
✗ Limited DevOps maturity
✗ Unclear domain boundariesService Design
服务设计
Domain-Driven Design
领域驱动设计
BOUNDED CONTEXTS:
┌─────────────────┐ ┌─────────────────┐
│ Orders │ │ Shipping │
│ Context │ │ Context │
│ ┌─────────────┐ │ │ ┌─────────────┐ │
│ │ Order │ │ │ │ Shipment │ │
│ │ LineItem │ │ │ │ Carrier │ │
│ │ Customer(ID)│ │ │ │ Address │ │
│ └─────────────┘ │ │ └─────────────┘ │
└─────────────────┘ └─────────────────┘
Each context has its own:
- Ubiquitous language
- Data model
- Business rulesBOUNDED CONTEXTS:
┌─────────────────┐ ┌─────────────────┐
│ Orders │ │ Shipping │
│ Context │ │ Context │
│ ┌─────────────┐ │ │ ┌─────────────┐ │
│ │ Order │ │ │ │ Shipment │ │
│ │ LineItem │ │ │ │ Carrier │ │
│ │ Customer(ID)│ │ │ │ Address │ │
│ └─────────────┘ │ │ └─────────────┘ │
└─────────────────┘ └─────────────────┘
Each context has its own:
- Ubiquitous language
- Data model
- Business rulesService Boundaries
服务边界
GOOD boundaries follow:
┌─────────────────────────────────────────┐
│ Business Capability │
│ - What the business does │
│ - e.g., Payment Processing, Inventory │
├─────────────────────────────────────────┤
│ Subdomain │
│ - Area of expertise │
│ - e.g., Pricing, Catalog, Customer │
├─────────────────────────────────────────┤
│ Single Responsibility │
│ - Does one thing well │
│ - Can explain in one sentence │
└─────────────────────────────────────────┘
BAD boundaries:
✗ Technical layers (UI service, DB service)
✗ CRUD operations (User CRUD service)
✗ Too granular (EmailSender service)GOOD boundaries follow:
┌─────────────────────────────────────────┐
│ Business Capability │
│ - What the business does │
│ - e.g., Payment Processing, Inventory │
├─────────────────────────────────────────┤
│ Subdomain │
│ - Area of expertise │
│ - e.g., Pricing, Catalog, Customer │
├─────────────────────────────────────────┤
│ Single Responsibility │
│ - Does one thing well │
│ - Can explain in one sentence │
└─────────────────────────────────────────┘
BAD boundaries:
✗ Technical layers (UI service, DB service)
✗ CRUD operations (User CRUD service)
✗ Too granular (EmailSender service)Service Size Guidelines
服务规模指南
Right-sized service:
- 2-pizza team can own it (5-8 people)
- Rewrite in 2-4 weeks if needed
- Clear, single business purpose
- Minimal external dependencies
- Own its data completely
Too big: Multiple teams needed, mixed concerns
Too small: Can't function independentlyRight-sized service:
- 2-pizza team can own it (5-8 people)
- Rewrite in 2-4 weeks if needed
- Clear, single business purpose
- Minimal external dependencies
- Own its data completely
Too big: Multiple teams needed, mixed concerns
Too small: Can't function independentlyCommunication Patterns
通信模式
Synchronous (Request/Response)
同步(请求/响应)
REST:
┌──────┐ HTTP GET /users/123 ┌──────┐
│Client│ ─────────────────────>│Server│
│ │<───────────────────── │ │
└──────┘ { "name": "John" } └──────┘
gRPC:
┌──────┐ Binary/Protobuf ┌──────┐
│Client│ ─────────────────────>│Server│
│ │<───────────────────── │ │
└──────┘ Strongly typed └──────┘
GraphQL:
┌──────┐ POST /graphql ┌──────┐
│Client│ ─────────────────────>│Server│
│ │<───────────────────── │ │
└──────┘ Flexible queries └──────┘REST:
┌──────┐ HTTP GET /users/123 ┌──────┐
│Client│ ─────────────────────>│Server│
│ │<───────────────────── │ │
└──────┘ { "name": "John" } └──────┘
gRPC:
┌──────┐ Binary/Protobuf ┌──────┐
│Client│ ─────────────────────>│Server│
│ │<───────────────────── │ │
└──────┘ Strongly typed └──────┘
GraphQL:
┌──────┐ POST /graphql ┌──────┐
│Client│ ─────────────────────>│Server│
│ │<───────────────────── │ │
└──────┘ Flexible queries └──────┘Asynchronous (Event-Driven)
异步(事件驱动)
MESSAGE QUEUE:
┌────────┐ ┌─────────┐ ┌────────┐
│Producer│ ───> │ Queue │ ───> │Consumer│
└────────┘ │(RabbitMQ│ └────────┘
│ SQS) │
└─────────┘
EVENT STREAMING:
┌────────┐ ┌─────────┐ ┌────────┐
│Producer│ ───> │ Topic │ ───> │Consumer│
└────────┘ │ (Kafka) │ ───> │Consumer│
└─────────┘ ───> │Consumer│
└────────┘MESSAGE QUEUE:
┌────────┐ ┌─────────┐ ┌────────┐
│Producer│ ───> │ Queue │ ───> │Consumer│
└────────┘ │(RabbitMQ│ └────────┘
│ SQS) │
└─────────┘
EVENT STREAMING:
┌────────┐ ┌─────────┐ ┌────────┐
│Producer│ ───> │ Topic │ ───> │Consumer│
└────────┘ │ (Kafka) │ ───> │Consumer│
└─────────┘ ───> │Consumer│
└────────┘Communication Comparison
通信模式对比
| Pattern | Use Case | Trade-offs |
|---|---|---|
| REST | CRUD, simple queries | Simple, but chatty |
| gRPC | High performance, internal | Fast, but complex |
| GraphQL | Flexible client needs | Flexible, but overhead |
| Message Queue | Task processing | Decoupled, but delay |
| Event Streaming | Event sourcing, analytics | Scalable, but complex |
| Pattern | Use Case | Trade-offs |
|---|---|---|
| REST | CRUD, simple queries | Simple, but chatty |
| gRPC | High performance, internal | Fast, but complex |
| GraphQL | Flexible client needs | Flexible, but overhead |
| Message Queue | Task processing | Decoupled, but delay |
| Event Streaming | Event sourcing, analytics | Scalable, but complex |
Data Management
数据管理
Database per Service
每个服务独立数据库
SEPARATE DATABASES:
┌────────┐ ┌────────┐ ┌────────┐
│Users │ │Orders │ │Products│
│Service │ │Service │ │Service │
├────────┤ ├────────┤ ├────────┤
│PostgreSQL│ │MongoDB │ │MySQL │
└────────┘ └────────┘ └────────┘
Benefits:
✓ Independent scaling
✓ Technology freedom
✓ No shared schema coupling
✓ Fault isolation
Challenges:
- No joins across services
- Eventual consistency
- Data duplicationSEPARATE DATABASES:
┌────────┐ ┌────────┐ ┌────────┐
│Users │ │Orders │ │Products│
│Service │ │Service │ │Service │
├────────┤ ├────────┤ ├────────┤
│PostgreSQL│ │MongoDB │ │MySQL │
└────────┘ └────────┘ └────────┘
Benefits:
✓ Independent scaling
✓ Technology freedom
✓ No shared schema coupling
✓ Fault isolation
Challenges:
- No joins across services
- Eventual consistency
- Data duplicationData Consistency Patterns
数据一致性模式
SAGA PATTERN (Choreography):
┌──────┐ ┌──────┐ ┌──────┐
│Order │─────>│Payment│─────>│Ship │
│Create│ │Process│ │Order │
└──────┘ └──────┘ └──────┘
│ │ │
└─────────────┴─────────────┘
Each service publishes events
that trigger next step
SAGA PATTERN (Orchestration):
┌────────────┐
│Orchestrator│
└────────────┘
/ │ \
↓ ↓ ↓
┌──────┐ ┌──────┐ ┌──────┐
│Order │ │Payment│ │Ship │
└──────┘ └──────┘ └──────┘
Central coordinator manages flowSAGA PATTERN (Choreography):
┌──────┐ ┌──────┐ ┌──────┐
│Order │─────>│Payment│─────>│Ship │
│Create│ │Process│ │Order │
└──────┘ └──────┘ └──────┘
│ │ │
└─────────────┴─────────────┘
Each service publishes events
that trigger next step
SAGA PATTERN (Orchestration):
┌────────────┐
│Orchestrator│
└────────────┘
/ │ \
↓ ↓ ↓
┌──────┐ ┌──────┐ ┌──────┐
│Order │ │Payment│ │Ship │
└──────┘ └──────┘ └──────┘
Central coordinator manages flowEvent Sourcing
事件溯源
Instead of storing current state:
┌────────────────────────────┐
│ Account: $500 │
└────────────────────────────┘
Store all events:
┌────────────────────────────┐
│ 1. AccountCreated $0 │
│ 2. Deposited $1000 │
│ 3. Withdrawn $300 │
│ 4. Withdrawn $200 │
│ Current: $500 │
└────────────────────────────┘
Benefits:
✓ Complete audit trail
✓ Temporal queries
✓ Event replay
✓ Natural fit for CQRSInstead of storing current state:
┌────────────────────────────┐
│ Account: $500 │
└────────────────────────────┘
Store all events:
┌────────────────────────────┐
│ 1. AccountCreated $0 │
│ 2. Deposited $1000 │
│ 3. Withdrawn $300 │
│ 4. Withdrawn $200 │
│ Current: $500 │
└────────────────────────────┘
Benefits:
✓ Complete audit trail
✓ Temporal queries
✓ Event replay
✓ Natural fit for CQRSAPI Gateway
API网关
Gateway Pattern
网关模式
┌─────────────┐
│ API Gateway │
└──────┬──────┘
┌──────────┬──┴──┬──────────┐
↓ ↓ ↓ ↓
┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
│Users │ │Orders │ │Products│ │Auth │
│Service │ │Service │ │Service │ │Service │
└────────┘ └────────┘ └────────┘ └────────┘
Gateway responsibilities:
- Request routing
- Authentication/Authorization
- Rate limiting
- Load balancing
- Request/Response transformation
- Caching
- Monitoring ┌─────────────┐
│ API Gateway │
└──────┬──────┘
┌──────────┬──┴──┬──────────┐
↓ ↓ ↓ ↓
┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
│Users │ │Orders │ │Products│ │Auth │
│Service │ │Service │ │Service │ │Service │
└────────┘ └────────┘ └────────┘ └────────┘
Gateway responsibilities:
- Request routing
- Authentication/Authorization
- Rate limiting
- Load balancing
- Request/Response transformation
- Caching
- MonitoringBFF (Backend for Frontend)
BFF(前端后端)
Mobile App Web App
│ │
↓ ↓
┌────────────┐ ┌────────────┐
│ Mobile BFF │ │ Web BFF │
└─────┬──────┘ └─────┬──────┘
│ │
┌──────┴────────────────┴──────┐
│ Internal APIs │
└───────────────────────────────┘
Each BFF:
- Optimized for its client
- Aggregates multiple services
- Handles client-specific logic Mobile App Web App
│ │
↓ ↓
┌────────────┐ ┌────────────┐
│ Mobile BFF │ │ Web BFF │
└─────┬──────┘ └─────┬──────┘
│ │
┌──────┴────────────────┴──────┐
│ Internal APIs │
└───────────────────────────────┘
Each BFF:
- Optimized for its client
- Aggregates multiple services
- Handles client-specific logicService Discovery
服务发现
Client-Side Discovery
客户端发现
┌──────┐ ┌──────────────┐
│Client│────>│Service │────> Service A (192.168.1.10)
│ │ │Registry │────> Service A (192.168.1.11)
│ │<────│(Consul, etcd)│────> Service A (192.168.1.12)
└──────┘ └──────────────┘
Client queries registry, then calls service directly.
Client handles load balancing.┌──────┐ ┌──────────────┐
│Client│────>│Service │────> Service A (192.168.1.10)
│ │ │Registry │────> Service A (192.168.1.11)
│ │<────│(Consul, etcd)│────> Service A (192.168.1.12)
└──────┘ └──────────────┘
Client queries registry, then calls service directly.
Client handles load balancing.Server-Side Discovery
服务端发现
┌──────┐ ┌─────────────┐ ┌──────────────┐
│Client│────>│Load Balancer│────>│Service │
│ │ │ │ │Registry │
└──────┘ └─────────────┘ └──────────────┘
│
┌────────┴────────┐
↓ ↓ ↓
Service Service Service
Load balancer handles discovery and routing.
Simpler for clients.┌──────┐ ┌─────────────┐ ┌──────────────┐
│Client│────>│Load Balancer│────>│Service │
│ │ │ │ │Registry │
└──────┘ └─────────────┘ └──────────────┘
│
┌────────┴────────┐
↓ ↓ ↓
Service Service Service
Load balancer handles discovery and routing.
Simpler for clients.Resilience Patterns
弹性模式
Circuit Breaker
断路器模式
States:
┌────────┐ Failures ┌────────┐
│ CLOSED │───────────────>│ OPEN │
│(normal)│ │(reject)│
└────────┘ └────────┘
↑ │
│ Timeout │
│ ┌────────────┐ │
└───│HALF-OPEN │<────────┘
│(test) │
└────────────┘
Implementation:
- Track failure count
- Open circuit after threshold
- Reject calls while open
- Periodically test with half-open
- Close circuit on successStates:
┌────────┐ Failures ┌────────┐
│ CLOSED │───────────────>│ OPEN │
│(normal)│ │(reject)│
└────────┘ └────────┘
↑ │
│ Timeout │
│ ┌────────────┐ │
└───│HALF-OPEN │<────────┘
│(test) │
└────────────┘
Implementation:
- Track failure count
- Open circuit after threshold
- Reject calls while open
- Periodically test with half-open
- Close circuit on successRetry Pattern
重试模式
typescript
async function withRetry<T>(
fn: () => Promise<T>,
maxAttempts: number = 3,
backoff: number = 1000,
): Promise<T> {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await fn();
} catch (error) {
if (attempt === maxAttempts) throw error;
// Exponential backoff with jitter
const delay = backoff * Math.pow(2, attempt - 1);
const jitter = delay * 0.1 * Math.random();
await sleep(delay + jitter);
}
}
}typescript
async function withRetry<T>(
fn: () => Promise<T>,
maxAttempts: number = 3,
backoff: number = 1000,
): Promise<T> {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await fn();
} catch (error) {
if (attempt === maxAttempts) throw error;
// Exponential backoff with jitter
const delay = backoff * Math.pow(2, attempt - 1);
const jitter = delay * 0.1 * Math.random();
await sleep(delay + jitter);
}
}
}Bulkhead Pattern
舱壁模式
Isolate resources to prevent cascade:
┌─────────────────────────────────────┐
│ Service A │
│ ┌─────────┐ ┌─────────┐ │
│ │Thread │ │Thread │ │
│ │Pool 1 │ │Pool 2 │ │
│ │(Service │ │(Service │ │
│ │ B) │ │ C) │ │
│ └─────────┘ └─────────┘ │
└─────────────────────────────────────┘
If Service C is slow, only Pool 2 is affected.
Service B calls continue normally.Isolate resources to prevent cascade:
┌─────────────────────────────────────┐
│ Service A │
│ ┌─────────┐ ┌─────────┐ │
│ │Thread │ │Thread │ │
│ │Pool 1 │ │Pool 2 │ │
│ │(Service │ │(Service │ │
│ │ B) │ │ C) │ │
│ └─────────┘ └─────────┘ │
└─────────────────────────────────────┘
If Service C is slow, only Pool 2 is affected.
Service B calls continue normally.Timeout Pattern
超时模式
typescript
async function withTimeout<T>(fn: () => Promise<T>, ms: number): Promise<T> {
return Promise.race([
fn(),
new Promise<T>((_, reject) =>
setTimeout(() => reject(new Error("Timeout")), ms),
),
]);
}
// Always set timeouts on external calls
const user = await withTimeout(
() => userService.getUser(id),
5000, // 5 second timeout
);typescript
async function withTimeout<T>(fn: () => Promise<T>, ms: number): Promise<T> {
return Promise.race([
fn(),
new Promise<T>((_, reject) =>
setTimeout(() => reject(new Error("Timeout")), ms),
),
]);
}
// Always set timeouts on external calls
const user = await withTimeout(
() => userService.getUser(id),
5000, // 5 second timeout
);Observability
可观测性
The Three Pillars
三大支柱
LOGS:
┌─────────────────────────────────────────┐
│ 2024-01-15 10:30:45 [INFO] OrderService │
│ Order created: { id: 123, user: 456 } │
└─────────────────────────────────────────┘
METRICS:
┌─────────────────────────────────────────┐
│ order_created_total: 1523 │
│ order_processing_seconds: 0.234 │
│ active_connections: 45 │
└─────────────────────────────────────────┘
TRACES:
┌─────────────────────────────────────────┐
│ [Request ID: abc123] │
│ ├─ Gateway: 2ms │
│ ├─ OrderService: 150ms │
│ │ ├─ UserService: 45ms │
│ │ └─ InventoryService: 80ms │
│ └─ Total: 152ms │
└─────────────────────────────────────────┘LOGS:
┌─────────────────────────────────────────┐
│ 2024-01-15 10:30:45 [INFO] OrderService │
│ Order created: { id: 123, user: 456 } │
└─────────────────────────────────────────┘
METRICS:
┌─────────────────────────────────────────┐
│ order_created_total: 1523 │
│ order_processing_seconds: 0.234 │
│ active_connections: 45 │
└─────────────────────────────────────────┘
TRACES:
┌─────────────────────────────────────────┐
│ [Request ID: abc123] │
│ ├─ Gateway: 2ms │
│ ├─ OrderService: 150ms │
│ │ ├─ UserService: 45ms │
│ │ └─ InventoryService: 80ms │
│ └─ Total: 152ms │
└─────────────────────────────────────────┘Distributed Tracing
分布式追踪
Trace Context Propagation:
┌──────┐ X-Trace-ID: abc ┌──────┐
│API │─────────────────>│Order │
│GW │ │Svc │
└──────┘ └──────┘
│
X-Trace-ID: abc │
↓
┌──────┐
│User │
│Svc │
└──────┘
Tools: Jaeger, Zipkin, AWS X-Ray, DatadogTrace Context Propagation:
┌──────┐ X-Trace-ID: abc ┌──────┐
│API │─────────────────>│Order │
│GW │ │Svc │
└──────┘ └──────┘
│
X-Trace-ID: abc │
↓
┌──────┐
│User │
│Svc │
└──────┘
Tools: Jaeger, Zipkin, AWS X-Ray, DatadogHealth Checks
健康检查
typescript
// Liveness: Is the service running?
app.get("/health/live", (req, res) => {
res.status(200).json({ status: "alive" });
});
// Readiness: Is the service ready to handle traffic?
app.get("/health/ready", async (req, res) => {
const dbHealthy = await checkDatabase();
const cacheHealthy = await checkCache();
if (dbHealthy && cacheHealthy) {
res.status(200).json({ status: "ready" });
} else {
res.status(503).json({
status: "not ready",
checks: { database: dbHealthy, cache: cacheHealthy },
});
}
});typescript
// Liveness: Is the service running?
app.get("/health/live", (req, res) => {
res.status(200).json({ status: "alive" });
});
// Readiness: Is the service ready to handle traffic?
app.get("/health/ready", async (req, res) => {
const dbHealthy = await checkDatabase();
const cacheHealthy = await checkCache();
if (dbHealthy && cacheHealthy) {
res.status(200).json({ status: "ready" });
} else {
res.status(503).json({
status: "not ready",
checks: { database: dbHealthy, cache: cacheHealthy },
});
}
});Deployment
部署
Containerization
容器化
dockerfile
undefineddockerfile
undefinedDockerfile
Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist ./dist
USER node
EXPOSE 3000
CMD ["node", "dist/main.js"]
undefinedFROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist ./dist
USER node
EXPOSE 3000
CMD ["node", "dist/main.js"]
undefinedKubernetes Basics
Kubernetes基础
yaml
undefinedyaml
undefineddeployment.yaml
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 3
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: order-service:1.0.0
ports:
- containerPort: 3000
resources:
limits:
cpu: "500m"
memory: "256Mi"
livenessProbe:
httpGet:
path: /health/live
port: 3000
readinessProbe:
httpGet:
path: /health/ready
port: 3000
---apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 3
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: order-service:1.0.0
ports:
- containerPort: 3000
resources:
limits:
cpu: "500m"
memory: "256Mi"
livenessProbe:
httpGet:
path: /health/live
port: 3000
readinessProbe:
httpGet:
path: /health/ready
port: 3000
---Testing Strategies
测试策略
Test Pyramid for Microservices
微服务测试金字塔
/\
/ \ E2E Tests
/────\ (Few, slow, brittle)
/ \
/────────\ Contract Tests
/ \ (Service boundaries)
/────────────\
/ \ Integration Tests
/────────────────\ (With dependencies)
/ \
/────────────────────\ Unit Tests
/ \ (Many, fast, isolated)
/________________________\ /\
/ \ E2E Tests
/────\ (Few, slow, brittle)
/ \
/────────\ Contract Tests
/ \ (Service boundaries)
/────────────\
/ \ Integration Tests
/────────────────\ (With dependencies)
/ \
/────────────────────\ Unit Tests
/ \ (Many, fast, isolated)
/________________________\Contract Testing
契约测试
typescript
// Consumer test (Order Service)
describe("User Service Contract", () => {
it("returns user by ID", async () => {
// Define expected interaction
await provider.addInteraction({
state: "user 123 exists",
uponReceiving: "a request for user 123",
withRequest: {
method: "GET",
path: "/users/123",
},
willRespondWith: {
status: 200,
body: {
id: "123",
name: like("John"),
email: like("john@example.com"),
},
},
});
// Test passes if consumer expectations match
});
});typescript
// Consumer test (Order Service)
describe("User Service Contract", () => {
it("returns user by ID", async () => {
// Define expected interaction
await provider.addInteraction({
state: "user 123 exists",
uponReceiving: "a request for user 123",
withRequest: {
method: "GET",
path: "/users/123",
},
willRespondWith: {
status: 200,
body: {
id: "123",
name: like("John"),
email: like("john@example.com"),
},
},
});
// Test passes if consumer expectations match
});
});Best Practices
最佳实践
DO:
建议:
- Start with a monolith, extract services later
- Define clear service boundaries
- Use asynchronous communication where possible
- Implement circuit breakers
- Centralize logging and monitoring
- Automate everything
- Design for failure
- Version your APIs
- 从单体应用开始,之后再提取服务
- 定义清晰的服务边界
- 尽可能使用异步通信
- 实现断路器
- 集中化日志与监控
- 自动化所有流程
- 为故障设计系统
- 对API进行版本管理
DON'T:
不建议:
- Create too many, too small services
- Share databases between services
- Make synchronous chains too deep
- Ignore distributed system complexities
- Couple services through shared libraries
- Skip contract testing
- Deploy without monitoring
- 创建过多过小的服务
- 服务之间共享数据库
- 同步调用链过深
- 忽略分布式系统的复杂性
- 通过共享库耦合服务
- 跳过契约测试
- 未配置监控就部署
Migration Checklist
迁移清单
Monolith to Microservices
从单体应用到微服务
- Map domain boundaries clearly
- Identify candidate services (start small)
- Establish CI/CD for new services
- Implement API gateway
- Set up service discovery
- Add distributed tracing
- Implement circuit breakers
- Extract first service (strangler fig pattern)
- Test extensively
- Monitor and iterate
- 清晰映射领域边界
- 识别候选服务(从小处着手)
- 为新服务建立CI/CD流程
- 实现API网关
- 搭建服务发现机制
- 添加分布式追踪
- 实现断路器
- 提取第一个服务(绞杀者模式)
- 全面测试
- 监控并迭代