1. 微服务与消息通信导论

在单体应用时代,一个 Node.js 项目往往把用户、订单、库存、支付等模块打包进同一个进程,通过函数调用直接协作。这种方式在业务简单时开发效率很高,但当团队规模扩大、发布频率提高、流量波动加剧时,任何一处改动都可能牵动整个系统,一次部署失败就可能让全部功能不可用。微服务架构正是为应对这类问题而出现的:它把系统按业务能力拆分为一组可以独立开发、独立部署、独立扩缩容的小型服务,每个服务围绕一个明确的业务边界构建,并拥有自己的数据与生命周期。

微服务架构的核心特征

理解微服务,关键不是“拆得多小”,而是拆完之后各服务之间如何协作。可以归纳为四个核心特征。

第一,围绕业务能力组织服务。例如电商系统可以拆成用户服务、商品服务、订单服务、库存服务、支付服务。每个服务对应一个业务领域,而不是按技术分层(如所有 Controller 一层、所有 DAO 一层)来切分。这样团队可以端到端负责一个业务能力,减少跨团队沟通成本。

第二,独立部署与独立扩缩容。订单服务在大促期间压力大,可以单独把订单服务从 2 个实例扩到 20 个实例,而不必把用户服务一起扩容。这要求服务之间不能共享同一个进程内存,也不能依赖同一个数据库事务来保证一致性。

第三,去中心化的数据管理。每个服务拥有自己的数据库或 schema,订单服务不直接读取库存服务的表,而是通过接口或消息来获取库存信息。这样服务之间的耦合从“数据库表结构”降到了“接口契约”或“消息格式”。

第四,面向失败设计。在分布式系统中,网络超时、服务宕机、消息丢失都是常态。微服务必须假设依赖方随时可能不可用,并通过超时、重试、熔断、降级、消息重投等手段保证整体系统仍能提供有损但可用的服务。

消息通信在解耦与弹性中的作用

服务拆分之后,服务之间需要通信。最直接的方式是同步调用,例如订单服务通过 HTTP 调用库存服务扣减库存。同步调用简单直观,但会带来强耦合:订单服务必须知道库存服务的地址,必须等待库存服务返回,库存服务变慢或宕机时订单服务也会被拖垮。

消息通信引入了一个中间层——消息代理(Broker),例如 RabbitMQ、Kafka、Redis Streams 或 NATS。服务不再直接调用对方,而是把事件或命令发送到 Broker,由 Broker 负责存储和转发。这样带来两个关键收益。

解耦:订单服务只需要把“订单已创建”事件发送到 Broker,不需要知道谁关心这个事件。库存服务、积分服务、通知服务可以各自订阅,新增一个“风控服务”时也不需要修改订单服务代码。服务之间从“点对点依赖”变成“事件发布/订阅”。

弹性:当库存服务暂时不可用时,消息可以暂存在 Broker 中,等库存服务恢复后再消费。订单服务不必因为库存服务宕机而失败。消息代理还可以配合重试队列、死信队列、消费者限流等机制,让系统在流量高峰或局部故障时保持稳定。

消息通信不是银弹。它把“同步等待”变成了“异步最终一致”,这意味着业务上需要接受短暂的数据不一致,并设计幂等消费、消息去重、顺序保证等机制。是否使用消息,取决于业务对一致性和实时性的要求。

Node.js 在微服务生态中的定位

Node.js 基于事件循环和非阻塞 I/O,天然适合处理大量并发连接和 I/O 密集型任务。在微服务架构中,Node.js 常被用于以下场景:

  • API 网关与 BFF:聚合多个后端服务,为前端提供定制化接口,利用异步 I/O 高效转发请求。
  • 实时通信服务:WebSocket、SSE、消息推送等长连接场景,Node.js 的事件驱动模型非常契合。
  • 消息消费者与生产者:通过 amqplib、kafkajs、ioredis 等库连接消息代理,处理事件流。
  • 轻量级业务服务:对于 CPU 计算不密集的业务服务,Node.js 可以用较少的资源支撑较高的并发。

需要注意的是,Node.js 的单线程事件循环不适合 CPU 密集型任务。如果某个服务需要大量图像处理、视频转码或复杂计算,应将其拆分为独立服务,或使用 Worker Threads、子进程,甚至换用其他语言实现。微服务的优势之一正是允许不同服务使用不同技术栈,Node.js 可以专注于它擅长的 I/O 与实时场景。

课程实战项目概览

本课程将围绕一个简化的电商订单履约场景展开。系统包含以下服务:

服务职责通信方式
API 网关接收前端请求,路由到订单服务HTTP
订单服务创建订单,发布“订单已创建”事件发布消息
库存服务订阅订单事件,扣减库存,发布“库存已扣减”事件订阅/发布消息
支付服务订阅库存事件,发起支付,发布“支付完成”事件订阅/发布消息
通知服务订阅支付完成事件,发送通知订阅消息

技术选型上,消息代理使用 RabbitMQ,Node.js 服务使用 Express 或 Fastify 提供 HTTP 接口,使用 amqplib 连接 RabbitMQ。每个服务独立运行、独立配置,通过环境变量指定端口和 Broker 地址。课程会逐步实现消息的发布、订阅、确认、重试、死信处理,并观察服务在故障和恢复过程中的行为。

电商订单履约微服务与消息通信拓扑 前端 / 客户端 HTTP 请求 API 网关 路由 / 鉴权 订单服务 创建订单 RabbitMQ 消息代理 Broker 发布事件 库存服务 扣减库存 支付服务 发起支付 通知服务 发送通知 死信队列 异常消息 订阅 订单已创建 订阅 库存已扣减 订阅 支付完成 发布 发布 重试失败 消息通信关键机制 • 发布/订阅:服务间通过事件解耦,新增消费者无需修改生产者 • 消息确认:消费者处理成功后 ACK,失败则 NACK 并进入重试或死信队列 • 幂等消费:同一消息可能重复投递,业务需保证重复处理不产生副作用