微服务架构
What — 是什么
微服务架构将单体应用拆分为多个独立部署的小服务,每个服务专注单一业务能力,通过 API/消息队列通信,独立开发/测试/部署/扩缩容。
核心概念:
- 服务拆分:按业务领域(DDD 限界上下文)拆分,每个服务拥有独立数据库
- 服务注册发现:服务实例动态注册地址,消费者通过注册中心查找(Consul/Nacos)
- API 网关:统一入口,路由转发、认证、限流、协议转换
- 配置中心:集中管理所有服务的配置,动态更新(Apollo/Nacos Config)
- 熔断降级:下游服务不可用时快速失败,防止级联故障(Circuit Breaker)
- 链路追踪:追踪请求在多个服务间的调用路径(Jaeger/Zipkin)
关键特性:
- 每个服务独立数据库,避免数据耦合
- 服务间通过 gRPC/REST/消息队列通信
- 独立部署,故障隔离
- 可按服务独立扩缩容
Why — 为什么
适用场景:
- 大型团队(10+ 开发者)协作
- 业务模块边界清晰
- 不同模块有不同的性能/扩展需求
- 需要独立部署和灰度发布
对比架构:
| 维度 | 单体架构 | 微服务架构 |
|---|---|---|
| 部署 | 简单(一个包) | 复杂(多服务) |
| 扩展 | 整体扩展 | 按需扩展 |
| 故障影响 | 全局 | 隔离 |
| 开发效率 | 小项目高 | 大项目高 |
| 运维复杂度 | 低 | 高 |
How — 怎么用
代码示例
// NestJS 微服务
const { NestFactory } = require('@nestjs/core');
const { MicroserviceOptions, Transport } = require('@nestjs/microservices');
const app = await NestFactory.createMicroservice(AppModule, {
transport: Transport.TCP,
options: { host: '0.0.0.0', port: 3001 }
});
// 消息处理
@MessagePattern('user.created')
async function handleUserCreated(data: CreateUserEvent) {
await this.notificationService.sendWelcome(data.userId);
}
// 客户端调用
@Injectable()
class OrderService {
constructor(@Inject('USER_SERVICE') private client: ClientProxy) {}
async getUser(id: string) {
return this.client.send({ cmd: 'get_user' }, { id }).toPromise();
}
}
常见问题与踩坑
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 分布式事务 | 跨服务数据一致性 | Saga 模式 + 事件溯源 |
| 服务间循环依赖 | 服务 A 调 B,B 调 A | 引入事件驱动解耦 |
| 调试困难 | 请求跨多个服务 | 链路追踪(Trace ID) |
| 数据一致性 | 各服务独立数据库 | 最终一致性 + 补偿事务 |
最佳实践
- 按业务领域拆分,不从技术层拆分
- 每个服务独立数据库
- 用 API 网关统一入口
- 实现熔断和降级防止级联故障
- 链路追踪串联跨服务调用
面试题
Q1: 微服务如何处理分布式事务?
两种主流方案:① Saga 模式——将长事务拆分为多个本地事务,每个步骤有补偿操作。失败时逆序执行补偿。适合业务流程明确的场景(订单→支付→库存)。② 事件溯源——所有状态变更以事件形式记录,通过重放事件重建状态。配合消息队列确保最终一致性。不推荐跨服务 2PC(性能差、耦合高)。
Q2: 微服务的服务发现如何实现?
两种模式:① 客户端发现——服务实例启动时向注册中心(Consul/Nacos)注册地址和健康状态,客户端从注册中心获取实例列表,自行选择(负载均衡)。② 服务端发现——客户端请求 API 网关/负载均衡器,由其查询注册中心并转发。客户端发现更灵活(可自定义策略),服务端发现更简单(客户端无需感知注册中心)。
相关链接: