主题
第 1 章:微服务架构
📋 本章概述
微服务架构是一种将单个应用程序拆分为一组小型、独立服务的架构风格。每个服务运行在自己的进程中,通过轻量级机制(通常是 HTTP API)进行通信。这种架构风格能够提高系统的可扩展性、可维护性和团队的独立性,是现代大型应用的标准架构模式。
学习目标
完成本章后,你将能够:
- ✅ 理解微服务架构的核心概念和原则
- ✅ 掌握服务拆分的策略和方法
- ✅ 实现 API 网关模式
- ✅ 配置服务发现和负载均衡
- ✅ 实现服务间通信(REST、gRPC、消息队列)
- ✅ 处理分布式事务和数据一致性
- ✅ 实现断路器和服务降级
- ✅ 搭建微服务监控系统
前置知识
- ✅ 熟练掌握 TypeScript 和 Node.js
- ✅ 理解 RESTful API 设计
- ✅ 了解基本的网络和 HTTP 协议
- ✅ 熟悉数据库操作
1. 微服务架构基础
1.1 什么是微服务架构
🦠 The Metaphor: The Cell Division (Organism) 单体应用就像是一个单细胞生物(如变形虫)。它所有的功能(消化、运动、繁殖)都挤在一个细胞膜里。简单,但脆弱。 微服务架构就像是一个多细胞生物(如人类)。
- User Service 是神经细胞。
- Order Service 是肌肉细胞。
- Payment Service 是血液细胞。
它们各司其职,通过化学信号(API)通信。如果一个肌肉细胞坏死了,人不会死(系统容错性)。如果需要跑得更快,身体会制造更多的肌肉细胞(独立扩展),而不需要让大脑也变大。
定义:
微服务架构是一种架构风格,它将应用构建为一组小型服务,每个服务:
- 运行在自己的进程中
- 围绕业务能力构建
- 可以独立部署
- 采用轻量级通信机制
与单体架构对比:
typescript
// ✅ 单体架构 - 所有功能在一个应用中
class MonolithicApp {
private userService: UserService;
private productService: ProductService;
private orderService: OrderService;
private paymentService: PaymentService;
// 所有服务紧密耦合在一起
async createOrder(userId: string, productIds: string[]) {
const user = await this.userService.getUser(userId);
const products = await this.productService.getProducts(productIds);
const order = await this.orderService.createOrder(user, products);
await this.paymentService.processPayment(order);
return order;
}
}
// ✅ 微服务架构 - 每个服务独立运行
// 用户服务 (User Service) - 独立应用
class UserServiceApp {
async getUser(userId: string) {
// 只负责用户相关逻辑
return await this.userRepository.findById(userId);
}
}
// 订单服务 (Order Service) - 独立应用
class OrderServiceApp {
async createOrder(orderData: CreateOrderDTO) {
// 通过 HTTP 调用其他服务
const user = await this.httpClient.get(`${USER_SERVICE_URL}/users/${orderData.userId}`);
const products = await this.httpClient.post(`${PRODUCT_SERVICE_URL}/products/batch`, {
ids: orderData.productIds
});
// 订单服务只负责订单逻辑
const order = await this.orderRepository.create({
userId: user.id,
products: products,
total: this.calculateTotal(products)
});
// 发送消息到支付服务
await this.messageQueue.publish('order.created', order);
return order;
}
}微服务架构的核心特征:
- 服务自治: 每个服务可以独立开发、测试、部署
- 去中心化: 没有中央控制,每个服务管理自己的数据
- 弹性: 单个服务的失败不会导致整个系统崩溃
- 可扩展: 可以针对特定服务进行扩展
- 技术多样性: 不同服务可以使用不同的技术栈
1.2 微服务的优势和挑战
优势:
typescript
/**
* 💡 微服务架构的主要优势
*/
// 1. 独立部署和扩展
// 场景: 电商系统在促销期间订单服务压力大
// 单体架构: 必须扩展整个应用
// 微服务: 只需扩展订单服务
// Kubernetes 配置示例
// apiVersion: apps/v1
// kind: Deployment
// metadata:
// name: order-service
// spec:
// replicas: 10 # 只扩展订单服务到 10 个实例
// ...
// 2. 技术栈灵活性
// 用户服务使用 Node.js + MongoDB
class UserService {
constructor(private mongoClient: MongoClient) {}
}
// 推荐服务使用 Python + TensorFlow (适合机器学习)
// class RecommendationService:
// def __init__(self, ml_model):
// self.model = ml_model
// 3. 团队独立性
// 团队 A 负责用户服务,团队 B 负责订单服务
// 他们可以独立开发、测试、部署,不互相阻塞
// 4. 故障隔离
class OrderService {
async getRecommendations(userId: string) {
try {
// 推荐服务挂了不影响核心订单功能
const recommendations = await this.recommendationServiceClient.get(userId);
return recommendations;
} catch (error) {
// 降级处理: 返回默认推荐
console.error('推荐服务不可用,使用默认推荐', error);
return this.getDefaultRecommendations();
}
}
}挑战:
typescript
/**
* ⚠️ 微服务架构的主要挑战
*/
// 1. 分布式系统复杂性
// 问题: 网络延迟、部分失败、数据一致性
class OrderService {
async createOrder(orderData: CreateOrderDTO) {
try {
// 调用用户服务 - 可能失败
const user = await this.userServiceClient.getUser(orderData.userId);
// 调用库存服务 - 可能失败
const stockCheck = await this.inventoryServiceClient.checkStock(orderData.items);
// 调用支付服务 - 可能失败
const payment = await this.paymentServiceClient.processPayment(orderData.payment);
// ❌ 如果支付成功但保存订单失败怎么办?
const order = await this.orderRepository.save({...});
return order;
} catch (error) {
// ⚠️ 需要复杂的错误处理和补偿逻辑
throw error;
}
}
}
// 2. 数据一致性
// 问题: 每个服务有自己的数据库,如何保证数据一致性?
// 场景: 用户下单后需要同时:
// - 创建订单记录 (订单数据库)
// - 扣减库存 (库存数据库)
// - 扣减积分 (用户数据库)
// ⚠️ 不能使用传统的数据库事务,因为数据在不同数据库中
// 3. 服务间通信开销
// 问题: 服务调用需要网络通信,比进程内调用慢得多
// 单体应用: 函数调用 (纳秒级)
const user = userService.getUser(userId); // 直接调用
// 微服务: HTTP 调用 (毫秒级)
const user = await fetch(`http://user-service/users/${userId}`); // 网络延迟
// 4. 测试复杂性
// 问题: 需要测试多个服务的交互
// ⚠️ 集成测试需要启动多个服务
// docker-compose up user-service product-service order-service payment-service
// 5. 运维复杂度
// 问题: 需要管理大量的服务实例
// 单体应用: 1 个应用
// 微服务: 10+ 个服务,每个服务可能有多个实例
// user-service: 3 实例
// product-service: 5 实例
// order-service: 10 实例
// ...1.3 何时使用微服务
🏛️ CS Master's Bridge: The Distributed Systems Trade-off
微服务本质上是将 函数调用 (Function Call) 替换为 网络调用 (Network Call)。
- Latency: 纳秒级 (ns) -> 毫秒级 (ms)。这是 10^6 倍的性能损失。
- Reliability: 进程内调用几乎总是成功;网络调用经常失败 (Network is unreliable)。
- Consistency: ACID 事务 -> 最终一致性 (BASE)。
Conway's Law (康威定律): "系统设计受限于组织沟通结构。"
- 如果你有 5 个人的团队,做微服务是自杀。
- 如果你有 500 个人的团队,做单体是自杀。
typescript
/**
* 💡 微服务适用场景判断
*/
// ✅ 适合使用微服务的场景:
// 1. 大型团队
// - 团队规模: 20+ 开发人员
// - 需要: 团队可以独立工作,减少协调成本
// 2. 复杂业务领域
// - 业务模块: 用户、商品、订单、支付、物流、营销...
// - 需要: 不同模块可以独立演进
// 3. 高扩展性要求
// - 场景: 不同模块有不同的负载特征
// - 例如: 商品浏览量大,但订单量相对小
// - 需要: 可以针对性扩展
// 4. 技术栈多样性需求
// - 场景: 不同模块适合不同技术
// - 例如: 推荐系统用 Python,核心服务用 Node.js
// 5. 持续交付要求
// - 场景: 需要频繁发布新功能
// - 需要: 各团队可以独立部署,不互相影响
// ❌ 不适合使用微服务的场景:
// 1. 小型应用
// - 团队规模: < 5 人
// - 问题: 微服务的复杂度大于收益
// 2. 业务不确定
// - 场景: 创业初期,业务快速变化
// - 问题: 服务边界难以确定,重构成本高
// 3. 简单的 CRUD 应用
// - 场景: 只是简单的数据库操作
// - 问题: 不需要复杂的架构
/**
* 🔍 决策框架
*/
class MicroserviceDecisionFramework {
/**
* 评估是否应该采用微服务架构
* @param criteria 评估标准
* @returns 是否适合微服务
*/
evaluate(criteria: {
teamSize: number; // 团队规模
domainComplexity: number; // 业务复杂度 (1-10)
scalabilityNeeds: number; // 扩展性需求 (1-10)
deploymentFrequency: number;// 部署频率 (次/月)
budgetForInfra: number; // 基础设施预算
}): { suitable: boolean; score: number; reasons: string[] } {
const reasons: string[] = [];
let score = 0;
// 团队规模评分
if (criteria.teamSize >= 20) {
score += 3;
reasons.push('✅ 团队规模足够大,可以分成多个独立团队');
} else if (criteria.teamSize >= 10) {
score += 1;
reasons.push('⚠️ 团队规模适中,可以考虑微服务');
} else {
score -= 2;
reasons.push('❌ 团队规模太小,微服务可能增加负担');
}
// 业务复杂度评分
if (criteria.domainComplexity >= 7) {
score += 3;
reasons.push('✅ 业务复杂度高,适合拆分');
} else if (criteria.domainComplexity >= 5) {
score += 1;
reasons.push('⚠️ 业务复杂度适中');
}
// 扩展性需求评分
if (criteria.scalabilityNeeds >= 7) {
score += 2;
reasons.push('✅ 扩展性需求高,微服务可以精准扩展');
}
// 部署频率评分
if (criteria.deploymentFrequency >= 10) {
score += 2;
reasons.push('✅ 部署频繁,微服务支持独立部署');
}
return {
suitable: score >= 5,
score,
reasons
};
}
}
// 使用示例
const framework = new MicroserviceDecisionFramework();
// 场景 1: 大型电商平台
const ecommercePlatform = framework.evaluate({
teamSize: 50,
domainComplexity: 9,
scalabilityNeeds: 10,
deploymentFrequency: 20,
budgetForInfra: 100000
});
console.log('电商平台评估:', ecommercePlatform);
// 输出: { suitable: true, score: 10, reasons: [...] }
// 场景 2: 小型 SaaS 应用
const smallSaaS = framework.evaluate({
teamSize: 5,
domainComplexity: 4,
scalabilityNeeds: 5,
deploymentFrequency: 8,
budgetForInfra: 5000
});
console.log('小型 SaaS 评估:', smallSaaS);
// 输出: { suitable: false, score: 0, reasons: [...] }2. 服务拆分策略
2.1 拆分原则
typescript
/**
* 💡 服务拆分的核心原则
*/
// 原则 1: 单一职责原则 (Single Responsibility Principle)
// 每个服务应该只有一个变更的理由
// ✅ 好的拆分
class UserService {
// 只负责用户相关的操作
async createUser(userData: CreateUserDTO) { }
async updateUser(userId: string, userData: UpdateUserDTO) { }
async getUserProfile(userId: string) { }
async authenticateUser(credentials: Credentials) { }
}
class OrderService {
// 只负责订单相关的操作
async createOrder(orderData: CreateOrderDTO) { }
async getOrderStatus(orderId: string) { }
async cancelOrder(orderId: string) { }
}
// ❌ 不好的拆分
class UserOrderService {
// 职责混乱,用户和订单耦合在一起
async createUser(userData: CreateUserDTO) { }
async createOrder(orderData: CreateOrderDTO) { }
async getUserOrders(userId: string) { }
}
// 原则 2: 业务能力边界 (Business Capability Boundary)
// 按照业务能力划分服务
/**
* 🔍 电商系统的业务能力分析
*/
class EcommerceDomainAnalysis {
// 识别核心业务能力
getBusinessCapabilities() {
return {
// 用户管理能力
userManagement: {
capabilities: ['注册', '登录', '个人信息管理', '地址管理'],
service: 'UserService'
},
// 商品目录能力
productCatalog: {
capabilities: ['商品CRUD', '分类管理', '搜索', '库存查询'],
service: 'ProductService'
},
// 订单处理能力
orderProcessing: {
capabilities: ['下单', '订单状态管理', '订单查询', '取消订单'],
service: 'OrderService'
},
// 支付能力
payment: {
capabilities: ['支付处理', '退款', '支付记录'],
service: 'PaymentService'
},
// 物流能力
shipping: {
capabilities: ['物流跟踪', '配送管理'],
service: 'ShippingService'
},
// 营销能力
marketing: {
capabilities: ['优惠券', '促销活动', '推荐系统'],
service: 'MarketingService'
}
};
}
}
// 原则 3: 数据独立性
// 每个服务拥有自己的数据库
// ✅ 好的设计 - 每个服务独立的数据库
class UserServiceWithDB {
private userDatabase: Database; // 用户服务专属数据库
async getUser(userId: string) {
return await this.userDatabase.query('SELECT * FROM users WHERE id = ?', [userId]);
}
}
class OrderServiceWithDB {
private orderDatabase: Database; // 订单服务专属数据库
async getOrder(orderId: string) {
return await this.orderDatabase.query('SELECT * FROM orders WHERE id = ?', [orderId]);
}
}
// ❌ 不好的设计 - 共享数据库
class UserServiceBad {
private sharedDatabase: Database; // ❌ 多个服务共享同一个数据库
async getUser(userId: string) {
// 可能会被其他服务的数据库变更影响
return await this.sharedDatabase.query('SELECT * FROM users WHERE id = ?', [userId]);
}
}
// 原则 4: 高内聚低耦合
// 服务内部紧密相关,服务之间松散耦合
// ✅ 高内聚示例
class ProductService {
// 这些方法都紧密相关,都是关于商品的
async createProduct(productData: CreateProductDTO) {
// 创建商品
const product = await this.productRepository.create(productData);
// 更新商品索引(仍然是商品相关)
await this.updateSearchIndex(product);
// 更新商品缓存(仍然是商品相关)
await this.cacheProduct(product);
return product;
}
private async updateSearchIndex(product: Product) {
// 内部方法,只为 createProduct 服务
}
private async cacheProduct(product: Product) {
// 内部方法,只为 createProduct 服务
}
}
// ✅ 低耦合示例
class OrderService {
constructor(
private orderRepository: OrderRepository,
// 通过接口与其他服务通信,而不是直接依赖
private userServiceClient: IUserServiceClient,
private productServiceClient: IProductServiceClient
) {}
async createOrder(orderData: CreateOrderDTO) {
// 通过 API 调用,而不是直接访问其他服务的数据库
const user = await this.userServiceClient.getUser(orderData.userId);
const product = await this.productServiceClient.getProduct(orderData.productId);
// 订单服务只管理订单数据
return await this.orderRepository.create({
userId: user.id,
productId: product.id,
total: product.price
});
}
}2.2 拆分方法
typescript
/**
* 💡 服务拆分的具体方法
*/
// 方法 1: 按业务领域拆分 (Domain-Driven Design)
// 使用 DDD 的限界上下文(Bounded Context)
/**
* 📚 电商系统的限界上下文
*/
interface BoundedContext {
name: string;
entities: string[];
aggregates: string[];
domainEvents: string[];
}
const ecommerceBoundedContexts: BoundedContext[] = [
{
name: '用户上下文',
entities: ['User', 'Address', 'Profile'],
aggregates: ['UserAggregate'],
domainEvents: ['UserRegistered', 'UserProfileUpdated']
},
{
name: '产品目录上下文',
entities: ['Product', 'Category', 'Inventory'],
aggregates: ['ProductAggregate'],
domainEvents: ['ProductCreated', 'PriceChanged', 'StockUpdated']
},
{
name: '订单上下文',
entities: ['Order', 'OrderItem', 'OrderStatus'],
aggregates: ['OrderAggregate'],
domainEvents: ['OrderCreated', 'OrderShipped', 'OrderCancelled']
}
];
// 每个限界上下文对应一个微服务
// 方法 2: 按变更频率拆分
// 将经常变更的部分和稳定的部分分离
class ServiceByChangeFrequency {
// 高变更频率服务 - 营销活动服务
// 原因: 促销规则经常变化
class MarketingService {
async createCampaign(campaign: Campaign) {
// 每周都可能有新的促销活动
}
}
// 低变更频率服务 - 用户服务
// 原因: 用户管理逻辑相对稳定
class UserService {
async createUser(user: User) {
// 用户注册流程很少改变
}
}
}
// 💡 好处: 可以更频繁地部署营销服务,而不影响稳定的用户服务
// 方法 3: 按团队边界拆分 (Conway's Law)
// 服务边界应该与团队边界对齐
/**
* 🔍 团队组织结构影响服务拆分
*/
class TeamBasedServices {
// 团队 A: 前台团队
teamA = {
name: '前台团队',
services: ['ProductCatalogService', 'SearchService', 'RecommendationService'],
responsibility: '用户可见的商品展示功能'
};
// 团队 B: 交易团队
teamB = {
name: '交易团队',
services: ['OrderService', 'PaymentService', 'CartService'],
responsibility: '订单和支付流程'
};
// 团队 C: 用户团队
teamC = {
name: '用户团队',
services: ['UserService', 'AuthService', 'ProfileService'],
responsibility: '用户账户和认证'
};
}
// 方法 4: 按技术需求拆分
class ServiceByTechRequirements {
// 需要高性能的服务 - 使用 Go
// class SearchServiceGo {
// // Go 实现,性能优秀
// }
// 需要机器学习的服务 - 使用 Python
// class RecommendationServicePython {
// // Python 实现,ML 库丰富
// }
// 常规业务服务 - 使用 TypeScript
class OrderServiceTS {
// TypeScript 实现,开发效率高
}
}
/**
* 🔍 实践: 识别服务边界
*/
class ServiceBoundaryIdentifier {
/**
* 分析实体之间的关系,识别聚合根
*/
analyzeEntityRelationships() {
// 示例: 电商订单聚合
// 聚合根: Order
// - 拥有 OrderItems
// - 拥有 ShippingAddress
// - 引用 User (不拥有)
// - 引用 Product (不拥有)
// 规则: 聚合内的实体应该在同一个服务中
// 聚合间的引用通过服务间调用
return {
OrderService: {
owns: ['Order', 'OrderItem', 'ShippingAddress'],
references: ['User', 'Product']
},
UserService: {
owns: ['User', 'UserProfile', 'Address'],
references: []
},
ProductService: {
owns: ['Product', 'Category', 'Inventory'],
references: []
}
};
}
/**
* 识别事务边界
* 需要在同一个事务中完成的操作应该在同一个服务中
*/
identifyTransactionBoundaries() {
// ✅ 同一个服务 - 可以使用数据库事务
class OrderService {
async createOrder(orderData: CreateOrderDTO) {
await this.db.transaction(async (trx) => {
// 这些操作必须全部成功或全部失败
const order = await trx('orders').insert({...});
await trx('order_items').insert([...]);
await trx('shipping_info').insert({...});
});
}
}
// ⚠️ 跨服务 - 需要使用分布式事务或最终一致性
class OrderServiceDistributed {
async createOrder(orderData: CreateOrderDTO) {
// 1. 创建订单
const order = await this.orderRepository.create({...});
// 2. 调用库存服务扣减库存 - 另一个数据库
await this.inventoryServiceClient.decreaseStock(orderData.items);
// 3. 调用支付服务 - 又一个数据库
await this.paymentServiceClient.processPayment(orderData.payment);
// ⚠️ 如果第 3 步失败,第 2 步已经执行,数据不一致!
}
}
}
}2.3 服务拆分实战案例
typescript
/**
* 🚀 实战案例: 重构单体应用为微服务
*/
// 原始单体应用
class MonolithicEcommerceApp {
// ❌ 所有功能混在一起
private userRepository: UserRepository;
private productRepository: ProductRepository;
private orderRepository: OrderRepository;
private paymentGateway: PaymentGateway;
async checkout(checkoutData: CheckoutData) {
// 1. 验证用户
const user = await this.userRepository.findById(checkoutData.userId);
if (!user) throw new Error('用户不存在');
// 2. 验证商品
const product = await this.productRepository.findById(checkoutData.productId);
if (!product) throw new Error('商品不存在');
// 3. 检查库存
if (product.stock < checkoutData.quantity) {
throw new Error('库存不足');
}
// 4. 扣减库存
await this.productRepository.updateStock(
product.id,
product.stock - checkoutData.quantity
);
// 5. 创建订单
const order = await this.orderRepository.create({
userId: user.id,
productId: product.id,
quantity: checkoutData.quantity,
total: product.price * checkoutData.quantity
});
// 6. 处理支付
const payment = await this.paymentGateway.charge({
amount: order.total,
userId: user.id
});
// 7. 更新订单状态
await this.orderRepository.updateStatus(order.id, 'PAID');
return order;
}
}
// 拆分后的微服务架构
// 1. 用户服务
class UserMicroservice {
constructor(private userRepository: UserRepository) {}
/**
* 获取用户信息
* @param userId 用户 ID
* @returns 用户信息
*/
async getUser(userId: string) {
const user = await this.userRepository.findById(userId);
if (!user) {
throw new NotFoundException('用户不存在');
}
return user;
}
/**
* 验证用户是否存在
* @param userId 用户 ID
* @returns 是否存在
*/
async validateUser(userId: string): Promise<boolean> {
const user = await this.userRepository.findById(userId);
return !!user;
}
}
// 2. 商品服务
class ProductMicroservice {
constructor(
private productRepository: ProductRepository,
private inventoryRepository: InventoryRepository
) {}
/**
* 获取商品信息
*/
async getProduct(productId: string) {
return await this.productRepository.findById(productId);
}
/**
* 检查并预留库存
* @returns 预留 ID,用于后续确认或取消
*/
async reserveStock(productId: string, quantity: number): Promise<string> {
const inventory = await this.inventoryRepository.findByProductId(productId);
if (inventory.available < quantity) {
throw new InsufficientStockError('库存不足');
}
// 创建库存预留记录
const reservation = await this.inventoryRepository.createReservation({
productId,
quantity,
status: 'RESERVED',
expiresAt: new Date(Date.now() + 10 * 60 * 1000) // 10 分钟后过期
});
// 减少可用库存
await this.inventoryRepository.decreaseAvailable(productId, quantity);
return reservation.id;
}
/**
* 确认库存扣减
*/
async confirmReservation(reservationId: string) {
const reservation = await this.inventoryRepository.findReservation(reservationId);
// 将预留转为实际扣减
await this.inventoryRepository.updateReservationStatus(reservationId, 'CONFIRMED');
await this.inventoryRepository.decreaseStock(
reservation.productId,
reservation.quantity
);
}
/**
* 取消库存预留
*/
async cancelReservation(reservationId: string) {
const reservation = await this.inventoryRepository.findReservation(reservationId);
// 恢复可用库存
await this.inventoryRepository.increaseAvailable(
reservation.productId,
reservation.quantity
);
await this.inventoryRepository.updateReservationStatus(reservationId, 'CANCELLED');
}
}
// 3. 订单服务
class OrderMicroservice {
constructor(
private orderRepository: OrderRepository,
private userServiceClient: UserServiceClient,
private productServiceClient: ProductServiceClient,
private paymentServiceClient: PaymentServiceClient,
private eventBus: EventBus
) {}
/**
* 创建订单
*/
async createOrder(orderData: CreateOrderDTO) {
// ✅ 调用用户服务验证用户
const userExists = await this.userServiceClient.validateUser(orderData.userId);
if (!userExists) {
throw new BadRequestException('用户不存在');
}
// ✅ 调用商品服务获取商品信息
const product = await this.productServiceClient.getProduct(orderData.productId);
// ✅ 调用商品服务预留库存
const reservationId = await this.productServiceClient.reserveStock(
orderData.productId,
orderData.quantity
);
try {
// 创建订单(状态: PENDING)
const order = await this.orderRepository.create({
userId: orderData.userId,
productId: orderData.productId,
quantity: orderData.quantity,
total: product.price * orderData.quantity,
status: 'PENDING',
reservationId
});
// ✅ 发送事件: 订单已创建
await this.eventBus.publish('order.created', {
orderId: order.id,
userId: order.userId,
total: order.total,
reservationId
});
return order;
} catch (error) {
// 失败时取消库存预留
await this.productServiceClient.cancelReservation(reservationId);
throw error;
}
}
/**
* 处理支付完成事件
*/
async handlePaymentCompleted(event: PaymentCompletedEvent) {
const order = await this.orderRepository.findById(event.orderId);
// 更新订单状态
await this.orderRepository.updateStatus(order.id, 'PAID');
// 确认库存扣减
await this.productServiceClient.confirmReservation(order.reservationId);
// 发送事件: 订单已支付
await this.eventBus.publish('order.paid', {
orderId: order.id,
userId: order.userId
});
}
}
// 4. 支付服务
class PaymentMicroservice {
constructor(
private paymentRepository: PaymentRepository,
private paymentGateway: PaymentGateway,
private eventBus: EventBus
) {}
/**
* 处理订单创建事件,发起支付
*/
async handleOrderCreated(event: OrderCreatedEvent) {
try {
// 调用第三方支付网关
const paymentResult = await this.paymentGateway.charge({
amount: event.total,
userId: event.userId,
orderId: event.orderId
});
// 保存支付记录
await this.paymentRepository.create({
orderId: event.orderId,
amount: event.total,
status: 'SUCCESS',
transactionId: paymentResult.transactionId
});
// 发送事件: 支付成功
await this.eventBus.publish('payment.completed', {
orderId: event.orderId,
amount: event.total
});
} catch (error) {
// 支付失败,发送事件
await this.eventBus.publish('payment.failed', {
orderId: event.orderId,
reason: error.message
});
}
}
}
/**
* 💡 拆分总结
*/
// 单体应用问题:
// - 所有逻辑耦合在一起
// - 难以独立扩展
// - 部署时互相影响
// - 团队协作困难
// 微服务架构优势:
// - 服务职责清晰
// - 可以独立部署和扩展
// - 使用事件驱动实现解耦
// - 团队可以独立开发
// 新增复杂性:
// - 需要处理服务间通信
// - 需要分布式事务或最终一致性
// - 需要更复杂的监控和运维3. API 网关
3.1 API 网关概念
🔌 The Metaphor: The Electrical Fuse (Circuit Breaker) 熔断器 (Circuit Breaker) 就像是家里的保险丝。 当电流过大(错误率过高/响应过慢)时,保险丝会熔断(Open State),切断电路。 这样可以防止电器被烧坏(防止级联故障/雪崩)。 过了一会儿,你可以试着合上闸(Half-Open State)。如果电流正常了,就恢复供电(Closed State);如果还是不行,就继续断开。 这保护了系统不会因为一个服务的故障而整体瘫痪。
🏨 The Metaphor: The Hotel Reception API 网关就是大酒店的前台。
- 没有网关:客人(客户端)必须自己去找厨师点菜,找保洁打扫房间,找财务结账。这太乱了,而且不安全(厨师不想让客人进厨房)。
- 有网关:客人只跟前台说话。“我要点菜”、“我要退房”。前台负责用对讲机联系厨师和财务。
- Cross-cutting Concerns: 前台还负责查验身份证(认证)、收押金(限流)、记录入住信息(日志)。这些杂活不需要厨师去操心。
🏛️ Architecture Pattern: API Gateway vs BFF
- API Gateway: 通用入口,负责 Cross-cutting concerns (Auth, Rate Limiting, Logging)。通常是基础设施层 (Nginx, Kong, AWS API Gateway)。
- BFF (Backend for Frontend): 为特定客户端 (Mobile, Web, IoT) 定制的聚合层。负责裁剪数据、聚合请求。通常由业务团队开发 (Node.js, GraphQL)。
Sidecar Pattern (Service Mesh): 在 Kubernetes 中,我们不再在代码里写 Retry/Circuit Breaker 逻辑,而是将其下沉到 Sidecar Proxy (Envoy/Istio)。
- App Container: 只管业务逻辑。
- Sidecar Container: 管网络通信、监控、安全。
typescript
/**
* 💡 API 网关 (API Gateway)
*
* 定义: API 网关是微服务架构中的单一入口点,
* 负责请求路由、协议转换、认证授权、限流等功能
*/
// ❌ 没有 API 网关的问题
// 客户端需要知道所有服务的地址
class ClientWithoutGateway {
async loadUserDashboard(userId: string) {
// 客户端直接调用多个服务
const user = await fetch('http://user-service:3001/users/' + userId);
const orders = await fetch('http://order-service:3002/orders?userId=' + userId);
const products = await fetch('http://product-service:3003/products/recommended?userId=' + userId);
// ⚠️ 问题:
// 1. 客户端需要知道所有服务的地址
// 2. 服务地址变更时客户端需要更新
// 3. 跨域问题(CORS)
// 4. 没有统一的认证
// 5. 多次 HTTP 请求,性能差
}
}
// ✅ 使用 API 网关
class ClientWithGateway {
async loadUserDashboard(userId: string) {
// 客户端只需要知道网关地址
const dashboard = await fetch('http://api-gateway/api/v1/dashboard/' + userId, {
headers: {
'Authorization': 'Bearer ' + this.authToken
}
});
// ✅ 优势:
// 1. 单一入口,客户端只需要知道网关地址
// 2. 网关负责路由到正确的服务
// 3. 统一处理认证和授权
// 4. 可以聚合多个服务的数据,减少客户端请求次数
}
}3.2 API 网关功能
typescript
/**
* 🔧 API 网关的核心功能
*/
import express, { Request, Response, NextFunction } from 'express';
import axios from 'axios';
import jwt from 'jsonwebtoken';
import rateLimit from 'express-rate-limit';
class APIGateway {
private app: express.Application;
// 服务注册表
private serviceRegistry = {
'user-service': 'http://user-service:3001',
'product-service': 'http://product-service:3002',
'order-service': 'http://order-service:3003',
'payment-service': 'http://payment-service:3004'
};
constructor() {
this.app = express();
this.setupMiddleware();
this.setupRoutes();
}
private setupMiddleware() {
this.app.use(express.json());
// 功能 1: CORS 处理
this.app.use(this.corsMiddleware());
// 功能 2: 请求日志
this.app.use(this.loggingMiddleware());
// 功能 3: 认证
this.app.use('/api/v1/protected/*', this.authenticationMiddleware());
// 功能 4: 限流
this.app.use('/api/v1/', this.rateLimitMiddleware());
}
/**
* 功能 1: CORS 处理
*/
private corsMiddleware() {
return (req: Request, res: Response, next: NextFunction) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
if (req.method === 'OPTIONS') {
res.sendStatus(200);
} else {
next();
}
};
}
/**
* 功能 2: 请求日志
*/
private loggingMiddleware() {
return (req: Request, res: Response, next: NextFunction) => {
const startTime = Date.now();
res.on('finish', () => {
const duration = Date.now() - startTime;
console.log({
timestamp: new Date().toISOString(),
method: req.method,
path: req.path,
statusCode: res.statusCode,
duration: `${duration}ms`,
userAgent: req.get('user-agent'),
ip: req.ip
});
});
next();
};
}
/**
* 功能 3: 认证中间件
*/
private authenticationMiddleware() {
return (req: Request, res: Response, next: NextFunction) => {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({ error: '缺少认证令牌' });
}
const token = authHeader.substring(7);
try {
// 验证 JWT
const decoded = jwt.verify(token, process.env.JWT_SECRET!) as any;
// 将用户信息附加到请求对象
req.user = {
id: decoded.userId,
email: decoded.email,
roles: decoded.roles
};
next();
} catch (error) {
return res.status(401).json({ error: '无效的认证令牌' });
}
};
}
/**
* 功能 4: 限流
*/
private rateLimitMiddleware() {
return rateLimit({
windowMs: 15 * 60 * 1000, // 15 分钟
max: 100, // 限制每个 IP 100 个请求
message: '请求过于频繁,请稍后再试',
standardHeaders: true,
legacyHeaders: false,
});
}
/**
* 功能 5: 请求路由
*/
private setupRoutes() {
// 路由到用户服务
this.app.all('/api/v1/users/*', async (req, res) => {
await this.proxyRequest(req, res, 'user-service');
});
// 路由到商品服务
this.app.all('/api/v1/products/*', async (req, res) => {
await this.proxyRequest(req, res, 'product-service');
});
// 路由到订单服务
this.app.all('/api/v1/orders/*', async (req, res) => {
await this.proxyRequest(req, res, 'order-service');
});
// 功能 6: 请求聚合
this.app.get('/api/v1/dashboard/:userId', async (req, res) => {
await this.aggregateDashboard(req, res);
});
}
/**
* 代理请求到目标服务
*/
private async proxyRequest(req: Request, res: Response, serviceName: string) {
const serviceUrl = this.serviceRegistry[serviceName];
if (!serviceUrl) {
return res.status(404).json({ error: '服务不存在' });
}
try {
// 移除 /api/v1/users 前缀,只保留后面的路径
const path = req.path.replace(/^\/api\/v1\/\w+/, '');
const targetUrl = `${serviceUrl}${path}`;
console.log(`[网关] 路由请求: ${req.method} ${req.path} -> ${targetUrl}`);
// 转发请求到目标服务
const response = await axios({
method: req.method,
url: targetUrl,
data: req.body,
params: req.query,
headers: {
// 转发原始请求头
...req.headers,
// 添加追踪 ID
'X-Request-ID': this.generateRequestId(),
// 添加用户信息(如果已认证)
'X-User-ID': req.user?.id,
}
});
// 返回响应
res.status(response.status).json(response.data);
} catch (error: any) {
console.error(`[网关] 请求失败:`, error.message);
if (error.response) {
// 目标服务返回了错误
res.status(error.response.status).json(error.response.data);
} else {
// 网络错误或服务不可用
res.status(503).json({ error: '服务暂时不可用' });
}
}
}
/**
* 功能 6: 请求聚合 - 组合多个服务的数据
*/
private async aggregateDashboard(req: Request, res: Response) {
const userId = req.params.userId;
try {
// 并行调用多个服务
const [userResponse, ordersResponse, recommendationsResponse] = await Promise.all([
axios.get(`${this.serviceRegistry['user-service']}/users/${userId}`),
axios.get(`${this.serviceRegistry['order-service']}/orders?userId=${userId}&limit=5`),
axios.get(`${this.serviceRegistry['product-service']}/products/recommended?userId=${userId}`)
]);
// 聚合数据
const dashboard = {
user: userResponse.data,
recentOrders: ordersResponse.data,
recommendations: recommendationsResponse.data
};
res.json(dashboard);
} catch (error: any) {
console.error('[网关] 聚合请求失败:', error.message);
res.status(500).json({ error: '无法加载仪表板数据' });
}
}
/**
* 功能 7: 响应缓存
*/
private cacheMiddleware() {
const cache = new Map<string, { data: any; timestamp: number }>();
const CACHE_TTL = 60 * 1000; // 60 秒
return (req: Request, res: Response, next: NextFunction) => {
// 只缓存 GET 请求
if (req.method !== 'GET') {
return next();
}
const cacheKey = req.path + JSON.stringify(req.query);
const cached = cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
console.log(`[网关] 缓存命中: ${cacheKey}`);
return res.json(cached.data);
}
// 拦截 res.json,保存到缓存
const originalJson = res.json.bind(res);
res.json = (data: any) => {
cache.set(cacheKey, { data, timestamp: Date.now() });
return originalJson(data);
};
next();
};
}
/**
* 功能 8: 断路器 - 防止级联失败
*/
private circuitBreakerMiddleware() {
const circuitBreakers = new Map<string, CircuitBreaker>();
return async (req: Request, res: Response, next: NextFunction) => {
const serviceName = this.getServiceNameFromPath(req.path);
if (!circuitBreakers.has(serviceName)) {
circuitBreakers.set(serviceName, new CircuitBreaker(serviceName));
}
const breaker = circuitBreakers.get(serviceName)!;
if (breaker.isOpen()) {
console.log(`[网关] 断路器打开: ${serviceName}`);
return res.status(503).json({
error: '服务暂时不可用',
reason: '断路器已打开'
});
}
next();
};
}
private getServiceNameFromPath(path: string): string {
// /api/v1/users/123 -> user-service
const match = path.match(/^\/api\/v1\/(\w+)/);
return match ? `${match[1]}-service` : 'unknown-service';
}
private generateRequestId(): string {
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}
start(port: number) {
this.app.listen(port, () => {
console.log(`[网关] API 网关运行在端口 ${port}`);
});
}
}
/**
* 断路器实现
*/
class CircuitBreaker {
private failureCount = 0;
private lastFailureTime = 0;
private state: 'CLOSED' | 'OPEN' | 'HALF_OPEN' = 'CLOSED';
private readonly FAILURE_THRESHOLD = 5; // 失败阈值
private readonly TIMEOUT = 60000; // 断路器打开时间: 60 秒
constructor(private serviceName: string) {}
isOpen(): boolean {
if (this.state === 'OPEN') {
// 检查是否可以进入半开状态
if (Date.now() - this.lastFailureTime > this.TIMEOUT) {
console.log(`[断路器] ${this.serviceName} 进入半开状态`);
this.state = 'HALF_OPEN';
return false;
}
return true;
}
return false;
}
recordSuccess() {
if (this.state === 'HALF_OPEN') {
console.log(`[断路器] ${this.serviceName} 关闭`);
this.state = 'CLOSED';
}
this.failureCount = 0;
}
recordFailure() {
this.failureCount++;
this.lastFailureTime = Date.now();
if (this.failureCount >= this.FAILURE_THRESHOLD) {
console.log(`[断路器] ${this.serviceName} 打开`);
this.state = 'OPEN';
}
}
}
/**
* 使用示例
*/
const gateway = new APIGateway();
gateway.start(8000);4. 服务发现和负载均衡
4.1 服务发现概念
typescript
/**
* 💡 服务发现 (Service Discovery)
*
* 问题: 微服务架构中,服务实例的 IP 和端口是动态的
* - 服务可能随时启动或关闭
* - 服务可能自动扩展(增加或减少实例)
* - 服务可能在不同的机器上运行
*
* 解决方案: 服务发现机制
* - 服务注册: 服务启动时向注册中心注册自己
* - 服务查询: 客户端从注册中心查询服务地址
* - 健康检查: 注册中心定期检查服务健康状态
*/
// ❌ 硬编码服务地址的问题
class OrderServiceWithHardcodedURL {
private userServiceURL = 'http://192.168.1.100:3001'; // ❌ 固定 IP
async getUser(userId: string) {
// 问题:
// 1. IP 地址改变时需要修改代码
// 2. 服务有多个实例时无法负载均衡
// 3. 服务宕机时无法自动切换
return await fetch(`${this.userServiceURL}/users/${userId}`);
}
}
// ✅ 使用服务发现
class OrderServiceWithDiscovery {
constructor(private serviceRegistry: ServiceRegistry) {}
async getUser(userId: string) {
// 动态获取服务地址
const userServiceURL = await this.serviceRegistry.getServiceURL('user-service');
return await fetch(`${userServiceURL}/users/${userId}`);
}
}4.2 服务注册中心实现
typescript
/**
* 服务注册中心 - 使用 Consul
*/
import Consul from 'consul';
interface ServiceInstance {
id: string;
name: string;
address: string;
port: number;
tags?: string[];
meta?: Record<string, string>;
}
class ServiceRegistry {
private consul: Consul.Consul;
constructor() {
this.consul = new Consul({
host: process.env.CONSUL_HOST || 'localhost',
port: process.env.CONSUL_PORT || '8500'
});
}
/**
* 注册服务
*/
async registerService(service: ServiceInstance): Promise<void> {
console.log(`[注册中心] 注册服务: ${service.name} (${service.address}:${service.port})`);
await this.consul.agent.service.register({
id: service.id,
name: service.name,
address: service.address,
port: service.port,
tags: service.tags,
meta: service.meta,
// 健康检查配置
check: {
http: `http://${service.address}:${service.port}/health`,
interval: '10s', // 每 10 秒检查一次
timeout: '5s', // 超时时间 5 秒
deregistercriticalserviceafter: '1m' // 1 分钟后注销不健康的服务
}
});
}
/**
* 注销服务
*/
async deregisterService(serviceId: string): Promise<void> {
console.log(`[注册中心] 注销服务: ${serviceId}`);
await this.consul.agent.service.deregister(serviceId);
}
/**
* 发现服务 - 获取所有健康的服务实例
*/
async discoverService(serviceName: string): Promise<ServiceInstance[]> {
const result = await this.consul.health.service({
service: serviceName,
passing: true // 只返回健康的实例
});
return result.map((entry: any) => ({
id: entry.Service.ID,
name: entry.Service.Service,
address: entry.Service.Address,
port: entry.Service.Port,
tags: entry.Service.Tags,
meta: entry.Service.Meta
}));
}
/**
* 获取服务 URL - 带负载均衡
*/
async getServiceURL(serviceName: string): Promise<string> {
const instances = await this.discoverService(serviceName);
if (instances.length === 0) {
throw new Error(`服务不可用: ${serviceName}`);
}
// 简单的轮询负载均衡
const instance = this.selectInstance(instances);
return `http://${instance.address}:${instance.port}`;
}
/**
* 负载均衡 - 轮询策略
*/
private instanceIndex = new Map<string, number>();
private selectInstance(instances: ServiceInstance[]): ServiceInstance {
const serviceName = instances[0].name;
const currentIndex = this.instanceIndex.get(serviceName) || 0;
const selectedInstance = instances[currentIndex % instances.length];
this.instanceIndex.set(serviceName, currentIndex + 1);
return selectedInstance;
}
}
/**
* 服务启动时自动注册
*/
class MicroserviceApp {
private serviceRegistry: ServiceRegistry;
private serviceId: string;
constructor(
private serviceName: string,
private port: number
) {
this.serviceRegistry = new ServiceRegistry();
this.serviceId = `${serviceName}-${process.pid}-${Date.now()}`;
}
async start() {
const app = express();
// 添加健康检查端点
app.get('/health', (req, res) => {
res.json({ status: 'UP', timestamp: new Date().toISOString() });
});
// 其他路由...
app.get('/users/:id', async (req, res) => {
// 业务逻辑
});
// 启动服务器
app.listen(this.port, async () => {
console.log(`[${this.serviceName}] 服务启动在端口 ${this.port}`);
// 注册到服务发现中心
await this.registerToConsul();
});
// 优雅关闭
process.on('SIGTERM', async () => {
await this.deregisterFromConsul();
process.exit(0);
});
}
private async registerToConsul() {
await this.serviceRegistry.registerService({
id: this.serviceId,
name: this.serviceName,
address: this.getLocalIP(),
port: this.port,
tags: ['api', 'v1'],
meta: {
version: '1.0.0',
environment: process.env.NODE_ENV || 'development'
}
});
}
private async deregisterFromConsul() {
await this.serviceRegistry.deregisterService(this.serviceId);
}
private getLocalIP(): string {
const interfaces = require('os').networkInterfaces();
for (const name of Object.keys(interfaces)) {
for (const iface of interfaces[name]) {
if (iface.family === 'IPv4' && !iface.internal) {
return iface.address;
}
}
}
return 'localhost';
}
}
// 使用示例
const userService = new MicroserviceApp('user-service', 3001);
userService.start();4.3 客户端负载均衡
👮 The Metaphor: The Traffic Cop (Load Balancer) 负载均衡器 (Load Balancer) 就像是路口的交警。 面对汹涌的车流(请求),交警指挥着交通:
- "你,走左边车道(Server A)。"
- "你,走右边车道(Server B)。"
他的目标是让所有车道都跑满但堵死。
- Round Robin: 轮流指。左、右、左、右... 公平但死板。
- Least Connections: 谁空闲指给谁。聪明。
- IP Hash: 认车牌。同一辆车永远指给同一条道(Session Sticky)。
typescript
/**
* 💡 负载均衡策略
*/
// 策略 1: 轮询 (Round Robin)
class RoundRobinLoadBalancer {
private currentIndex = 0;
selectInstance(instances: ServiceInstance[]): ServiceInstance {
const selected = instances[this.currentIndex % instances.length];
this.currentIndex++;
return selected;
}
}
// 策略 2: 随机
class RandomLoadBalancer {
selectInstance(instances: ServiceInstance[]): ServiceInstance {
const randomIndex = Math.floor(Math.random() * instances.length);
return instances[randomIndex];
}
}
// 策略 3: 最少连接数
class LeastConnectionsLoadBalancer {
private connections = new Map<string, number>();
selectInstance(instances: ServiceInstance[]): ServiceInstance {
// 选择连接数最少的实例
let minConnections = Infinity;
let selectedInstance = instances[0];
for (const instance of instances) {
const connections = this.connections.get(instance.id) || 0;
if (connections < minConnections) {
minConnections = connections;
selectedInstance = instance;
}
}
return selectedInstance;
}
incrementConnections(instanceId: string) {
const current = this.connections.get(instanceId) || 0;
this.connections.set(instanceId, current + 1);
}
decrementConnections(instanceId: string) {
const current = this.connections.get(instanceId) || 0;
this.connections.set(instanceId, Math.max(0, current - 1));
}
}
// 策略 4: 加权轮询
interface WeightedServiceInstance extends ServiceInstance {
weight: number; // 权重,性能好的实例权重更高
}
class WeightedRoundRobinLoadBalancer {
private currentWeight = 0;
selectInstance(instances: WeightedServiceInstance[]): WeightedServiceInstance {
const totalWeight = instances.reduce((sum, inst) => sum + inst.weight, 0);
let selectedInstance = instances[0];
let currentSum = 0;
for (const instance of instances) {
currentSum += instance.weight;
if (this.currentWeight < currentSum) {
selectedInstance = instance;
break;
}
}
this.currentWeight = (this.currentWeight + 1) % totalWeight;
return selectedInstance;
}
}
/**
* 带重试和故障转移的服务客户端
*/
class ResilientServiceClient {
constructor(
private serviceRegistry: ServiceRegistry,
private loadBalancer: RoundRobinLoadBalancer
) {}
async call<T>(
serviceName: string,
path: string,
options: RequestInit = {}
): Promise<T> {
const maxRetries = 3;
let lastError: Error | null = null;
// 获取所有可用实例
const instances = await this.serviceRegistry.discoverService(serviceName);
if (instances.length === 0) {
throw new Error(`没有可用的服务实例: ${serviceName}`);
}
// 尝试多个实例
for (let i = 0; i < Math.min(maxRetries, instances.length); i++) {
const instance = this.loadBalancer.selectInstance(instances);
const url = `http://${instance.address}:${instance.port}${path}`;
try {
console.log(`[客户端] 调用 ${serviceName}: ${url}`);
const response = await fetch(url, {
...options,
// 设置超时
signal: AbortSignal.timeout(5000)
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json() as T;
} catch (error: any) {
console.error(`[客户端] 调用失败: ${url}`, error.message);
lastError = error;
// 从实例列表中移除失败的实例,尝试下一个
const index = instances.indexOf(instance);
instances.splice(index, 1);
if (instances.length === 0) {
break;
}
}
}
throw new Error(`服务调用失败: ${serviceName}, ${lastError?.message}`);
}
}5. 服务间通信
5.1 同步通信 - REST API
typescript
/**
* 💡 REST API - 最常用的同步通信方式
*/
// 服务提供方 - 用户服务
class UserServiceAPI {
setupRoutes(app: express.Application) {
// GET /users/:id - 获取用户
app.get('/users/:id', async (req, res) => {
try {
const user = await this.userRepository.findById(req.params.id);
if (!user) {
return res.status(404).json({ error: '用户不存在' });
}
res.json(user);
} catch (error) {
console.error('[用户服务] 获取用户失败:', error);
res.status(500).json({ error: '内部服务器错误' });
}
});
// POST /users - 创建用户
app.post('/users', async (req, res) => {
try {
const user = await this.userRepository.create(req.body);
res.status(201).json(user);
} catch (error) {
console.error('[用户服务] 创建用户失败:', error);
res.status(500).json({ error: '内部服务器错误' });
}
});
}
}
// 服务消费方 - 订单服务调用用户服务
class OrderService {
constructor(
private userServiceClient: ResilientServiceClient
) {}
async createOrder(orderData: CreateOrderDTO) {
// 调用用户服务验证用户
const user = await this.userServiceClient.call<User>(
'user-service',
`/users/${orderData.userId}`,
{ method: 'GET' }
);
// 创建订单
const order = await this.orderRepository.create({
userId: user.id,
...orderData
});
return order;
}
}5.2 同步通信 - gRPC
🔧 Under the Hood: Protobuf & HTTP/2
- Protobuf (Protocol Buffers): 二进制序列化格式。比 JSON 小 3-10 倍,解析快 20-100 倍。
- JSON: 文本解析 (Scanner/Parser),CPU 密集。
- Protobuf: 简单的内存复制和指针移动。
- HTTP/2: 多路复用 (Multiplexing)。在一个 TCP 连接上并发处理多个请求。解决了 HTTP/1.1 的 Head-of-Line Blocking 问题。
Use Case: 内部服务间通信 (East-West traffic) 用 gRPC;外部通信 (North-South traffic) 用 REST/GraphQL。
typescript
/**
* 💡 gRPC - 高性能的 RPC 框架
*
* 优势:
* - 使用 Protocol Buffers,序列化性能高
* - 支持双向流
* - 类型安全
* - 多语言支持
*/
// 1. 定义 Protocol Buffer (user.proto)
/*
syntax = "proto3";
package user;
service UserService {
rpc GetUser (GetUserRequest) returns (User);
rpc CreateUser (CreateUserRequest) returns (User);
rpc ListUsers (ListUsersRequest) returns (stream User);
}
message GetUserRequest {
string user_id = 1;
}
message CreateUserRequest {
string name = 1;
string email = 2;
}
message ListUsersRequest {
int32 limit = 1;
int32 offset = 2;
}
message User {
string id = 1;
string name = 2;
string email = 3;
string created_at = 4;
}
*/
// 2. 服务端实现
import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';
class UserServiceGRPC {
private server: grpc.Server;
constructor(private userRepository: UserRepository) {
this.server = new grpc.Server();
this.loadProtoAndRegister();
}
private loadProtoAndRegister() {
const packageDefinition = protoLoader.loadSync('./proto/user.proto', {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
});
const userProto = grpc.loadPackageDefinition(packageDefinition).user as any;
this.server.addService(userProto.UserService.service, {
GetUser: this.getUser.bind(this),
CreateUser: this.createUser.bind(this),
ListUsers: this.listUsers.bind(this)
});
}
/**
* 实现 GetUser RPC
*/
private async getUser(
call: grpc.ServerUnaryCall<any, any>,
callback: grpc.sendUnaryData<any>
) {
try {
const userId = call.request.user_id;
const user = await this.userRepository.findById(userId);
if (!user) {
return callback({
code: grpc.status.NOT_FOUND,
message: '用户不存在'
});
}
callback(null, user);
} catch (error: any) {
callback({
code: grpc.status.INTERNAL,
message: error.message
});
}
}
/**
* 实现 CreateUser RPC
*/
private async createUser(
call: grpc.ServerUnaryCall<any, any>,
callback: grpc.sendUnaryData<any>
) {
try {
const user = await this.userRepository.create(call.request);
callback(null, user);
} catch (error: any) {
callback({
code: grpc.status.INTERNAL,
message: error.message
});
}
}
/**
* 实现 ListUsers RPC - 流式响应
*/
private async listUsers(call: grpc.ServerWritableStream<any, any>) {
try {
const { limit, offset } = call.request;
const users = await this.userRepository.findMany({ limit, offset });
// 逐个发送用户数据
for (const user of users) {
call.write(user);
}
call.end();
} catch (error: any) {
call.destroy(new Error(error.message));
}
}
start(port: number) {
this.server.bindAsync(
`0.0.0.0:${port}`,
grpc.ServerCredentials.createInsecure(),
(error, port) => {
if (error) {
console.error('[gRPC] 启动失败:', error);
return;
}
console.log(`[gRPC] 服务运行在端口 ${port}`);
this.server.start();
}
);
}
}
// 3. 客户端实现
class UserServiceGRPCClient {
private client: any;
constructor(serviceAddress: string) {
const packageDefinition = protoLoader.loadSync('./proto/user.proto', {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
});
const userProto = grpc.loadPackageDefinition(packageDefinition).user as any;
this.client = new userProto.UserService(
serviceAddress,
grpc.credentials.createInsecure()
);
}
async getUser(userId: string): Promise<User> {
return new Promise((resolve, reject) => {
this.client.GetUser({ user_id: userId }, (error: any, user: User) => {
if (error) {
reject(error);
} else {
resolve(user);
}
});
});
}
async createUser(userData: CreateUserRequest): Promise<User> {
return new Promise((resolve, reject) => {
this.client.CreateUser(userData, (error: any, user: User) => {
if (error) {
reject(error);
} else {
resolve(user);
}
});
});
}
async listUsers(limit: number, offset: number): Promise<User[]> {
return new Promise((resolve, reject) => {
const users: User[] = [];
const call = this.client.ListUsers({ limit, offset });
call.on('data', (user: User) => {
users.push(user);
});
call.on('end', () => {
resolve(users);
});
call.on('error', (error: any) => {
reject(error);
});
});
}
}
// 使用示例
const grpcClient = new UserServiceGRPCClient('localhost:50051');
const user = await grpcClient.getUser('user-123');5.3 异步通信 - 消息队列
typescript
/**
* 💡 消息队列 - 异步解耦的通信方式
*
* 优势:
* - 异步处理,不阻塞主流程
* - 削峰填谷,应对流量峰值
* - 服务解耦,发送方和接收方独立
* - 可靠性,消息持久化防止丢失
*/
// 使用 RabbitMQ
import * as amqp from 'amqplib';
class MessageQueue {
private connection: amqp.Connection | null = null;
private channel: amqp.Channel | null = null;
async connect(url: string = 'amqp://localhost') {
this.connection = await amqp.connect(url);
this.channel = await this.connection.createChannel();
console.log('[消息队列] 已连接到 RabbitMQ');
}
/**
* 发布消息到交换机
*/
async publish(exchange: string, routingKey: string, message: any) {
if (!this.channel) {
throw new Error('消息队列未连接');
}
// 确保交换机存在
await this.channel.assertExchange(exchange, 'topic', { durable: true });
// 发布消息
this.channel.publish(
exchange,
routingKey,
Buffer.from(JSON.stringify(message)),
{
persistent: true, // 持久化消息
timestamp: Date.now(),
contentType: 'application/json'
}
);
console.log(`[消息队列] 发布消息: ${exchange}.${routingKey}`, message);
}
/**
* 订阅消息
*/
async subscribe(
exchange: string,
queueName: string,
routingKeys: string[],
handler: (message: any) => Promise<void>
) {
if (!this.channel) {
throw new Error('消息队列未连接');
}
// 确保交换机存在
await this.channel.assertExchange(exchange, 'topic', { durable: true });
// 创建队列
await this.channel.assertQueue(queueName, { durable: true });
// 绑定路由键
for (const routingKey of routingKeys) {
await this.channel.bindQueue(queueName, exchange, routingKey);
}
// 设置预取数量 - 一次只处理一条消息
await this.channel.prefetch(1);
// 消费消息
await this.channel.consume(
queueName,
async (msg) => {
if (!msg) return;
try {
const content = JSON.parse(msg.content.toString());
console.log(`[消息队列] 收到消息: ${msg.fields.routingKey}`, content);
// 处理消息
await handler(content);
// 确认消息
this.channel!.ack(msg);
} catch (error) {
console.error('[消息队列] 处理消息失败:', error);
// 拒绝消息并重新入队
this.channel!.nack(msg, false, true);
}
},
{ noAck: false } // 手动确认
);
console.log(`[消息队列] 开始监听队列: ${queueName}`);
}
async close() {
await this.channel?.close();
await this.connection?.close();
}
}
/**
* 🚀 实战示例: 订单系统使用消息队列
*/
// 订单服务 - 发布订单事件
class OrderServiceWithMQ {
constructor(
private orderRepository: OrderRepository,
private messageQueue: MessageQueue
) {}
async createOrder(orderData: CreateOrderDTO) {
// 1. 创建订单
const order = await this.orderRepository.create({
...orderData,
status: 'PENDING'
});
console.log('[订单服务] 订单已创建:', order.id);
// 2. 发布订单创建事件
await this.messageQueue.publish(
'orders', // 交换机
'order.created', // 路由键
{
orderId: order.id,
userId: order.userId,
items: order.items,
total: order.total,
timestamp: new Date().toISOString()
}
);
return order;
}
}
// 支付服务 - 订阅订单事件
class PaymentServiceWithMQ {
constructor(
private paymentRepository: PaymentRepository,
private messageQueue: MessageQueue
) {}
async start() {
// 订阅订单创建事件
await this.messageQueue.subscribe(
'orders', // 交换机
'payment-service', // 队列名称
['order.created'], // 路由键
this.handleOrderCreated.bind(this)
);
}
private async handleOrderCreated(event: any) {
console.log('[支付服务] 处理订单创建事件:', event.orderId);
try {
// 处理支付
const payment = await this.processPayment(event);
// 发布支付成功事件
await this.messageQueue.publish(
'payments',
'payment.completed',
{
orderId: event.orderId,
paymentId: payment.id,
amount: event.total,
timestamp: new Date().toISOString()
}
);
} catch (error) {
console.error('[支付服务] 支付失败:', error);
// 发布支付失败事件
await this.messageQueue.publish(
'payments',
'payment.failed',
{
orderId: event.orderId,
reason: (error as Error).message,
timestamp: new Date().toISOString()
}
);
}
}
private async processPayment(event: any) {
// 支付处理逻辑
return await this.paymentRepository.create({
orderId: event.orderId,
amount: event.total,
status: 'SUCCESS'
});
}
}
// 通知服务 - 订阅支付事件
class NotificationServiceWithMQ {
constructor(
private emailService: EmailService,
private messageQueue: MessageQueue
) {}
async start() {
// 订阅支付相关事件
await this.messageQueue.subscribe(
'payments',
'notification-service',
['payment.completed', 'payment.failed'],
this.handlePaymentEvent.bind(this)
);
}
private async handlePaymentEvent(event: any) {
const routingKey = event.type;
if (routingKey === 'payment.completed') {
await this.sendPaymentSuccessEmail(event);
} else if (routingKey === 'payment.failed') {
await this.sendPaymentFailureEmail(event);
}
}
private async sendPaymentSuccessEmail(event: any) {
console.log('[通知服务] 发送支付成功邮件:', event.orderId);
// 发送邮件逻辑
}
private async sendPaymentFailureEmail(event: any) {
console.log('[通知服务] 发送支付失败邮件:', event.orderId);
// 发送邮件逻辑
}
}6. 分布式事务
6.1 分布式事务的挑战
typescript
/**
* ⚠️ 分布式事务问题
*
* 场景: 用户下单需要:
* 1. 创建订单 (订单服务/订单数据库)
* 2. 扣减库存 (库存服务/库存数据库)
* 3. 扣减余额 (用户服务/用户数据库)
*
* 问题: 如果第 3 步失败,前两步已经执行,数据不一致!
*
* 传统解决方案: 数据库事务 (ACID)
* ❌ 无法使用,因为数据在不同的数据库中
*
* 分布式解决方案:
* 1. 两阶段提交 (2PC) - 强一致性,性能差
* 2. 三阶段提交 (3PC) - 改进版 2PC
* 3. Saga 模式 - 最终一致性,性能好
* 4. TCC 模式 - Try-Confirm-Cancel
*/6.2 Saga 模式实现
🏛️ Pattern: Event Sourcing & CQRS
- Event Sourcing (事件溯源): 不存当前状态,只存状态变更事件 (Events)。当前状态 =
reduce(events)。
- 优势: 完美的审计日志,可回溯任意时间点状态。
- 劣势: 查询慢 (需要 Snapshot)。
- CQRS (Command Query Responsibility Segregation): 读写分离。
- Write Model: 针对高并发写入优化 (Event Store)。
- Read Model: 针对查询优化 (Materialized Views, Elasticsearch)。
- Sync: 通过 Event Bus 异步更新 Read Model (最终一致性)。
typescript
/**
* 💡 Saga 模式
*
* 原理: 将分布式事务拆分为一系列本地事务
* - 每个本地事务更新数据库并发布事件
* - 如果某个步骤失败,执行补偿事务回滚之前的操作
*
* 两种实现方式:
* 1. 编排式 (Orchestration) - 中央协调器
* 2. 编排式 (Choreography) - 事件驱动
*/
// 方式 1: 编排式 Saga - 使用中央协调器
class OrderSagaOrchestrator {
constructor(
private orderService: OrderServiceClient,
private inventoryService: InventoryServiceClient,
private paymentService: PaymentServiceClient,
private sagaRepository: SagaRepository
) {}
async createOrder(orderData: CreateOrderDTO): Promise<Order> {
// 创建 Saga 实例
const saga = await this.sagaRepository.create({
type: 'CREATE_ORDER',
data: orderData,
status: 'STARTED',
steps: []
});
try {
// 步骤 1: 创建订单
console.log('[Saga] 步骤 1: 创建订单');
const order = await this.orderService.createOrder(orderData);
await this.sagaRepository.addStep(saga.id, {
name: 'CREATE_ORDER',
status: 'COMPLETED',
data: { orderId: order.id }
});
try {
// 步骤 2: 预留库存
console.log('[Saga] 步骤 2: 预留库存');
const reservation = await this.inventoryService.reserveStock({
productId: orderData.productId,
quantity: orderData.quantity
});
await this.sagaRepository.addStep(saga.id, {
name: 'RESERVE_STOCK',
status: 'COMPLETED',
data: { reservationId: reservation.id }
});
try {
// 步骤 3: 处理支付
console.log('[Saga] 步骤 3: 处理支付');
const payment = await this.paymentService.processPayment({
orderId: order.id,
amount: order.total
});
await this.sagaRepository.addStep(saga.id, {
name: 'PROCESS_PAYMENT',
status: 'COMPLETED',
data: { paymentId: payment.id }
});
// 所有步骤成功
console.log('[Saga] 所有步骤完成');
await this.sagaRepository.updateStatus(saga.id, 'COMPLETED');
// 步骤 4: 确认库存扣减
await this.inventoryService.confirmReservation(reservation.id);
// 步骤 5: 更新订单状态
await this.orderService.markAsPaid(order.id);
return order;
} catch (error) {
// 支付失败 - 补偿步骤 2
console.log('[Saga] 支付失败,开始补偿');
await this.compensateReserveStock(reservation.id, saga.id);
throw error;
}
} catch (error) {
// 库存预留失败 - 补偿步骤 1
console.log('[Saga] 库存预留失败,开始补偿');
await this.compensateCreateOrder(order.id, saga.id);
throw error;
}
} catch (error) {
// 订单创建失败 - 直接失败
console.log('[Saga] Saga 失败');
await this.sagaRepository.updateStatus(saga.id, 'FAILED');
throw error;
}
}
/**
* 补偿事务: 取消订单
*/
private async compensateCreateOrder(orderId: string, sagaId: string) {
console.log('[Saga] 补偿: 取消订单', orderId);
try {
await this.orderService.cancelOrder(orderId);
await this.sagaRepository.addStep(sagaId, {
name: 'COMPENSATE_CREATE_ORDER',
status: 'COMPLETED',
data: { orderId }
});
} catch (error) {
console.error('[Saga] 补偿失败:', error);
// 记录补偿失败,需要人工介入
await this.sagaRepository.addStep(sagaId, {
name: 'COMPENSATE_CREATE_ORDER',
status: 'FAILED',
data: { orderId, error: (error as Error).message }
});
}
}
/**
* 补偿事务: 释放库存
*/
private async compensateReserveStock(reservationId: string, sagaId: string) {
console.log('[Saga] 补偿: 释放库存', reservationId);
try {
await this.inventoryService.cancelReservation(reservationId);
await this.sagaRepository.addStep(sagaId, {
name: 'COMPENSATE_RESERVE_STOCK',
status: 'COMPLETED',
data: { reservationId }
});
} catch (error) {
console.error('[Saga] 补偿失败:', error);
await this.sagaRepository.addStep(sagaId, {
name: 'COMPENSATE_RESERVE_STOCK',
status: 'FAILED',
data: { reservationId, error: (error as Error).message }
});
}
}
}
// Saga 状态存储
interface SagaStep {
name: string;
status: 'PENDING' | 'COMPLETED' | 'FAILED';
data: any;
timestamp: Date;
}
interface SagaInstance {
id: string;
type: string;
status: 'STARTED' | 'COMPLETED' | 'FAILED' | 'COMPENSATING';
data: any;
steps: SagaStep[];
createdAt: Date;
updatedAt: Date;
}
class SagaRepository {
async create(saga: Omit<SagaInstance, 'id' | 'createdAt' | 'updatedAt'>): Promise<SagaInstance> {
// 保存到数据库
return { ...saga, id: generateId(), createdAt: new Date(), updatedAt: new Date() };
}
async addStep(sagaId: string, step: Omit<SagaStep, 'timestamp'>): Promise<void> {
// 添加步骤到数据库
}
async updateStatus(sagaId: string, status: SagaInstance['status']): Promise<void> {
// 更新 Saga 状态
}
async findById(sagaId: string): Promise<SagaInstance | null> {
// 从数据库查询
return null;
}
}
// 方式 2: 编排式 Saga - 事件驱动
/**
* 💡 编排式 Saga 实现
*
* 流程:
* 1. 订单服务创建订单,发布 order.created 事件
* 2. 库存服务监听事件,预留库存,发布 stock.reserved 事件
* 3. 支付服务监听事件,处理支付,发布 payment.completed 事件
* 4. 订单服务监听事件,更新订单状态
*
* 如果任何步骤失败,发布相应的补偿事件
*/
class OrderServiceChoreography {
constructor(
private orderRepository: OrderRepository,
private messageQueue: MessageQueue
) {
this.setupEventHandlers();
}
async createOrder(orderData: CreateOrderDTO) {
// 创建订单
const order = await this.orderRepository.create({
...orderData,
status: 'PENDING'
});
// 发布事件
await this.messageQueue.publish('saga', 'order.created', {
orderId: order.id,
productId: orderData.productId,
quantity: orderData.quantity,
amount: order.total
});
return order;
}
private setupEventHandlers() {
// 监听支付完成事件
this.messageQueue.subscribe(
'saga',
'order-service-saga',
['payment.completed', 'stock.reservation.failed', 'payment.failed'],
async (event: any) => {
const routingKey = event.type;
if (routingKey === 'payment.completed') {
// 更新订单状态为已支付
await this.orderRepository.updateStatus(event.orderId, 'PAID');
} else if (routingKey === 'stock.reservation.failed' || routingKey === 'payment.failed') {
// 取消订单
await this.orderRepository.updateStatus(event.orderId, 'CANCELLED');
}
}
);
}
}
class InventoryServiceChoreography {
constructor(
private inventoryRepository: InventoryRepository,
private messageQueue: MessageQueue
) {
this.setupEventHandlers();
}
private setupEventHandlers() {
// 监听订单创建事件
this.messageQueue.subscribe(
'saga',
'inventory-service-saga',
['order.created', 'payment.failed'],
async (event: any) => {
const routingKey = event.type;
if (routingKey === 'order.created') {
try {
// 预留库存
const reservation = await this.inventoryRepository.reserveStock(
event.productId,
event.quantity
);
// 发布库存预留成功事件
await this.messageQueue.publish('saga', 'stock.reserved', {
orderId: event.orderId,
reservationId: reservation.id,
amount: event.amount
});
} catch (error) {
// 发布库存预留失败事件
await this.messageQueue.publish('saga', 'stock.reservation.failed', {
orderId: event.orderId,
reason: (error as Error).message
});
}
} else if (routingKey === 'payment.failed') {
// 补偿: 释放库存
await this.inventoryRepository.cancelReservation(event.reservationId);
}
}
);
}
}7. 监控和追踪
7.1 分布式追踪
typescript
/**
* 💡 分布式追踪 (Distributed Tracing)
*
* 问题: 一个请求可能经过多个服务,如何追踪完整的调用链路?
*
* 解决方案: 使用 OpenTelemetry 进行分布式追踪
*/
import { trace, context, SpanStatusCode } from '@opentelemetry/api';
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { JaegerExporter } from '@opentelemetry/exporter-jaeger';
import { Resource } from '@opentelemetry/resources';
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
/**
* 初始化追踪
*/
function initTracing(serviceName: string) {
const provider = new NodeTracerProvider({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: serviceName,
}),
});
// 导出到 Jaeger
const exporter = new JaegerExporter({
endpoint: 'http://localhost:14268/api/traces',
});
provider.addSpanProcessor(new SpanProcessor(exporter));
provider.register();
console.log(`[追踪] 服务 ${serviceName} 追踪已初始化`);
}
/**
* Express 中间件 - 自动创建 span
*/
function tracingMiddleware(serviceName: string) {
const tracer = trace.getTracer(serviceName);
return (req: Request, res: Response, next: NextFunction) => {
// 从请求头中提取追踪上下文
const traceId = req.header('X-Trace-Id') || generateTraceId();
const spanId = req.header('X-Span-Id') || generateSpanId();
const parentSpanId = req.header('X-Parent-Span-Id');
// 创建 span
const span = tracer.startSpan(`${req.method} ${req.path}`, {
attributes: {
'http.method': req.method,
'http.url': req.url,
'http.target': req.path,
'http.user_agent': req.get('user-agent'),
}
});
// 将 span 放入上下文
const ctx = trace.setSpan(context.active(), span);
// 记录响应
res.on('finish', () => {
span.setAttribute('http.status_code', res.statusCode);
if (res.statusCode >= 400) {
span.setStatus({
code: SpanStatusCode.ERROR,
message: `HTTP ${res.statusCode}`
});
}
span.end();
});
// 继续处理请求
context.with(ctx, () => next());
};
}
/**
* 服务间调用时传递追踪上下文
*/
class TracedHttpClient {
async call(url: string, options: RequestInit = {}) {
const tracer = trace.getTracer('http-client');
const span = tracer.startSpan(`HTTP ${options.method || 'GET'}`);
try {
// 将追踪上下文注入请求头
const headers = {
...options.headers,
'X-Trace-Id': span.spanContext().traceId,
'X-Span-Id': span.spanContext().spanId,
'X-Parent-Span-Id': getCurrentSpanId()
};
const response = await fetch(url, {
...options,
headers
});
span.setAttribute('http.status_code', response.status);
span.setStatus({ code: SpanStatusCode.OK });
return response;
} catch (error) {
span.recordException(error as Error);
span.setStatus({
code: SpanStatusCode.ERROR,
message: (error as Error).message
});
throw error;
} finally {
span.end();
}
}
}7.2 指标监控
typescript
/**
* 💡 Prometheus 指标监控
*/
import promClient from 'prom-client';
class MetricsCollector {
private register: promClient.Registry;
// HTTP 请求计数器
private httpRequestCounter: promClient.Counter;
// HTTP 请求延迟直方图
private httpRequestDuration: promClient.Histogram;
// 活跃连接数
private activeConnections: promClient.Gauge;
// 数据库查询延迟
private dbQueryDuration: promClient.Histogram;
constructor(serviceName: string) {
this.register = new promClient.Registry();
// 添加默认指标
promClient.collectDefaultMetrics({ register: this.register });
// HTTP 请求计数
this.httpRequestCounter = new promClient.Counter({
name: `${serviceName}_http_requests_total`,
help: 'Total number of HTTP requests',
labelNames: ['method', 'path', 'status'],
registers: [this.register]
});
// HTTP 请求延迟
this.httpRequestDuration = new promClient.Histogram({
name: `${serviceName}_http_request_duration_seconds`,
help: 'Duration of HTTP requests in seconds',
labelNames: ['method', 'path', 'status'],
buckets: [0.1, 0.5, 1, 2, 5],
registers: [this.register]
});
// 活跃连接数
this.activeConnections = new promClient.Gauge({
name: `${serviceName}_active_connections`,
help: 'Number of active connections',
registers: [this.register]
});
// 数据库查询延迟
this.dbQueryDuration = new promClient.Histogram({
name: `${serviceName}_db_query_duration_seconds`,
help: 'Duration of database queries in seconds',
labelNames: ['operation', 'table'],
buckets: [0.01, 0.05, 0.1, 0.5, 1],
registers: [this.register]
});
}
/**
* 记录 HTTP 请求
*/
recordHttpRequest(method: string, path: string, statusCode: number, duration: number) {
this.httpRequestCounter.labels(method, path, statusCode.toString()).inc();
this.httpRequestDuration.labels(method, path, statusCode.toString()).observe(duration);
}
/**
* 更新活跃连接数
*/
setActiveConnections(count: number) {
this.activeConnections.set(count);
}
/**
* 记录数据库查询
*/
recordDbQuery(operation: string, table: string, duration: number) {
this.dbQueryDuration.labels(operation, table).observe(duration);
}
/**
* 获取指标
*/
async getMetrics(): Promise<string> {
return await this.register.metrics();
}
}
/**
* Express 中间件 - 收集 HTTP 指标
*/
function metricsMiddleware(metricsCollector: MetricsCollector) {
return (req: Request, res: Response, next: NextFunction) => {
const startTime = Date.now();
metricsCollector.setActiveConnections(
metricsCollector['activeConnections'].hashMap[''].value + 1
);
res.on('finish', () => {
const duration = (Date.now() - startTime) / 1000;
metricsCollector.recordHttpRequest(
req.method,
req.route?.path || req.path,
res.statusCode,
duration
);
metricsCollector.setActiveConnections(
metricsCollector['activeConnections'].hashMap[''].value - 1
);
});
next();
};
}
/**
* 暴露指标端点
*/
function setupMetricsEndpoint(app: express.Application, collector: MetricsCollector) {
app.get('/metrics', async (req, res) => {
res.set('Content-Type', promClient.register.contentType);
res.end(await collector.getMetrics());
});
}8. 总结和最佳实践
8.1 微服务架构最佳实践
typescript
/**
* ✅ 微服务架构最佳实践清单
*/
const microservicesBestPractices = {
// 1. 服务拆分
serviceSplitting: {
principles: [
'按业务能力拆分,而不是技术层次',
'保持服务的独立性和自治性',
'避免过度拆分,保持适当的粒度',
'服务应该有清晰的边界和职责'
],
antiPatterns: [
'❌ 按数据库表拆分服务',
'❌ 服务之间频繁的循环依赖',
'❌ 服务拆分过细,增加复杂度'
]
},
// 2. 数据管理
dataManagement: {
principles: [
'每个服务拥有自己的数据库',
'通过 API 访问其他服务的数据',
'使用事件来保持数据同步',
'接受最终一致性'
],
antiPatterns: [
'❌ 多个服务共享同一个数据库',
'❌ 直接访问其他服务的数据库',
'❌ 分布式事务'
]
},
// 3. 通信
communication: {
principles: [
'同步调用用于请求-响应(REST/gRPC)',
'异步消息用于事件通知',
'实现超时和重试机制',
'使用断路器防止级联失败'
],
patterns: [
'API 网关统一入口',
'服务发现动态路由',
'客户端负载均衡',
'消息队列解耦服务'
]
},
// 4. 弹性和容错
resilience: {
principles: [
'实现健康检查端点',
'使用断路器模式',
'实现优雅降级',
'记录详细日志'
],
patterns: [
'重试机制',
'超时控制',
'舱壁模式',
'限流和熔断'
]
},
// 5. 监控和可观测性
observability: {
required: [
'分布式追踪 (Jaeger/Zipkin)',
'指标监控 (Prometheus)',
'日志聚合 (ELK/Loki)',
'健康检查和告警'
],
metrics: [
'请求速率',
'错误率',
'响应延迟',
'系统资源使用'
]
},
// 6. 部署和运维
deployment: {
practices: [
'容器化 (Docker)',
'容器编排 (Kubernetes)',
'CI/CD 自动化',
'蓝绿部署或金丝雀发布',
'版本化 API'
]
}
};8.2 常见陷阱和解决方案
typescript
/**
* ⚠️ 常见陷阱和解决方案
*/
const commonPitfalls = [
{
problem: '分布式单体 (Distributed Monolith)',
description: '虽然拆分了服务,但服务之间紧密耦合,必须一起部署',
solution: [
'减少服务间的同步调用',
'使用异步消息解耦',
'确保服务可以独立部署',
'避免共享数据库'
]
},
{
problem: '过度拆分',
description: '服务拆分太细,导致管理复杂度急剧上升',
solution: [
'从较大的服务开始,根据需要逐步拆分',
'合并紧密耦合的服务',
'权衡复杂度和收益'
]
},
{
problem: '数据一致性问题',
description: '分布式环境下难以保证强一致性',
solution: [
'接受最终一致性',
'使用 Saga 模式处理分布式事务',
'实现补偿机制',
'记录所有状态变更'
]
},
{
problem: '级联失败',
description: '一个服务故障导致整个系统瘫痪',
solution: [
'实现断路器',
'设置合理的超时',
'使用限流保护服务',
'实现优雅降级'
]
},
{
problem: '监控和调试困难',
description: '请求跨越多个服务,难以定位问题',
solution: [
'实现分布式追踪',
'使用关联 ID 追踪请求',
'集中化日志管理',
'建立完善的监控体系'
]
}
];9. 练习题
练习 1: 服务拆分设计
问题: 设计一个社交媒体平台的微服务架构,包含以下功能:
- 用户管理(注册、登录、个人资料)
- 帖子发布和浏览
- 评论和点赞
- 关注和粉丝
- 消息通知
- 内容推荐
要求:
- 识别核心业务能力
- 设计服务边界
- 定义服务间的通信方式
- 说明数据存储策略
练习 2: API 网关实现
问题: 实现一个 API 网关,支持:
- 请求路由
- 认证和授权
- 限流(每分钟 100 个请求)
- 请求日志
- 断路器
练习 3: Saga 模式
问题: 实现一个旅游预订系统的 Saga:
- 预订航班
- 预订酒店
- 预订租车
- 处理支付
如果任何步骤失败,需要取消之前的预订。
练习 4: 服务发现
问题: 实现一个简单的服务注册中心,支持:
- 服务注册
- 服务发现
- 健康检查
- 自动注销不健康的服务
10. 延伸阅读
推荐书籍
- 《微服务设计》 by Sam Newman
- 《微服务架构设计模式》 by Chris Richardson
- 《构建微服务》 by Sam Newman
在线资源
工具和框架
- 服务框架: NestJS, Express, Fastify
- 服务发现: Consul, Etcd
- API 网关: Kong, Traefik
- 消息队列: RabbitMQ, Kafka
- 监控: Prometheus, Grafana, Jaeger
下一章: 第 2 章 - 数据库和 ORM
由于内容非常详实,我将继续创建剩余的章节。让我继续编写第 2 章 - 数据库和 ORM:
由于内容非常长,我需要分批创建文件。让我继续创建各章节的内容。现在让我创建完整的项目文档和练习题,然后更新进度追踪文档。
<function_calls>
<invoke name="TodoWrite">
<parameter name="todos">[
{
"id": "1",
"content": "创建阶段 4 目录结构和主 README.md",
"status": "completed"
},
{
"id": "2",
"content": "编写第 1 章: 微服务架构 (01-microservices/README.md)",
"status": "in_progress"
},
{
"id": "3",
"content": "编写第 2 章: 数据库和 ORM (02-database-orm/README.md)",
"status": "pending"
},
{
"id": "4",
"content": "编写第 3 章: 安全 (03-security/README.md)",
"status": "pending"
},
{
"id": "5",
"content": "编写第 4 章: DevOps 和部署 (04-devops-deployment/README.md)",
"status": "pending"
},
{
"id": "6",
"content": "编写第 5 章: 前端高级 (05-frontend-advanced/README.md)",
"status": "pending"
},
{
"id": "7",
"content": "编写第 6 章: 系统设计 (06-system-design/README.md)",
"status": "pending"
},
{
"id": "8",
"content": "编写全栈电商平台项目指南 (projects/ecommerce-platform/README.md)",
"status": "pending"
},
{
"id": "9",
"content": "编写练习题和评估 (exercises/README.md)",
"status": "pending"
},
{
"id": "10",
"content": "更新任务追踪文档,标记阶段 4 任务为已完成",
"status": "pending"
}
]