NestJS 微服务怎么设计?Transport 层、消息模式和架构选型
NestJS 的微服务支持不是"把单体拆成微服务"的完整方案,而是提供了跨服务通信的 Transport 层。你可以用同样的 Controller/Service 写法,底层换成 Redis/RabbitMQ/Kafka/gRPC 通信,应用代码几乎不用改。
微服务模式 vs 单体
NestJS 应用默认是 HTTP 单体。改成微服务只需要换一个传输层:
typescript// main.ts - HTTP 单体 const app = await NestFactory.create(AppModule); await app.listen(3000); // main.ts - 微服务 const app = await NestFactory.createMicroservice(AppModule, { transport: Transport.REDIS, options: { url: 'redis://localhost:6379' }, }); await app.listen();
微服务模式下,应用不再监听 HTTP 端口,而是通过消息队列接收请求。
通信模式
请求/响应(Request/Response)
和 HTTP 一样——发请求等响应。适合需要立即拿到结果的场景。
typescript// 服务端 @MessagePattern('get_user') getUser(@Payload() id: string) { return this.usersService.findOne(id); } // 客户端 @Injectable() export class AppService { constructor(@Inject('USER_SERVICE') private client: ClientProxy) {} getUser(id: string) { return this.client.send('get_user', id); } }
send 返回 Observable,可以用 .toPromise() 或 firstValueFrom() 转成 Promise。
事件驱动(Event-driven)
发出去不等响应——"fire and forget"。适合通知类场景(发邮件、写日志、更新缓存)。
typescript// 发布者 this.client.emit('user_created', { userId: user.id }); // 订阅者 @EventPattern('user_created') handleUserCreated(@Payload() data: { userId: string }) { // 发送欢迎邮件、更新统计等 }
emit 不返回结果,订阅者可以有多个(广播模式)。请求/响应模式只会有一个服务响应。
Transport 选型
| Transport | 适用场景 | 特点 |
|---|---|---|
| TCP | 开发/测试 | 默认,零依赖 |
| Redis | 简单生产环境 | Pub/Sub 模式,需要 Redis |
| RabbitMQ | 企业级 | 消息确认、重试、路由 |
| Kafka | 高吞吐 | 日志流、事件溯源 |
| gRPC | 高性能 RPC | 强类型、Protobuf |
开发阶段用 TCP,不需要装任何中间件。生产环境看需求:简单场景用 Redis,复杂路由和消息确认用 RabbitMQ,日志和流处理用 Kafka。
混合模式:HTTP + 微服务
大部分现实应用需要一个 HTTP 入口 + 内部微服务通信。NestJS 支持混合模式:
typescript// main.ts const app = await NestFactory.create(AppModule); const microservice = app.connectMicroservice({ transport: Transport.REDIS, options: { url: 'redis://localhost:6379' }, }); await app.startAllMicroservices(); await app.listen(3000);
这样应用同时监听 HTTP(给前端用)和 Redis 消息(给其他微服务用)。API Gateway 模式通常是这种——外部请求走 HTTP,内部服务间走消息队列。
什么时候该用微服务
不要因为"微服务是趋势"就拆。微服务引入的复杂度(部署、调试、数据一致性)对小团队是灾难。
适合微服务的信号:
- 团队超过 10 人,需要独立部署不同模块
- 某个模块有独立的伸缩需求(比如报表生成吃 CPU,需要单独扩容)
- 不同模块的技术栈差异大(一个用 Node,一个用 Python)
不适合微服务的信号:
- 3-5 人团队
- 模块间数据高度耦合
- 没有自动化部署和监控基础设施
大多数项目从模块化单体(Modular Monolith)开始更安全——NestJS 的 Module 本身就是天然的模块边界,等真正需要时再拆微服务,代码几乎不用改,只需要换 Transport。