Skip to content

01 - 为什么学习 Watermill ​

一、同步通信的局限 ​

在微服务架构早期,服务间通信多采用同步 HTTP/gRPC 调用。这种模式简单直观,但随着系统规模增长,问题逐渐显现:

紧耦合。调用方必须知道被调用方的地址、端口,被调用方不可用时请求直接失败。服务A调用服务B,B再调用C,形成调用链——任意一环出问题,整个链路崩溃。

扩展困难。当需要在订单创建后同时通知库存、支付、通知三个服务时,订单服务必须逐一调用,代码随下游服务数量线性增长。每新增一个消费者,就要修改订单服务代码。

一致性挑战。同步调用中,订单写库成功后调用库存失败,已写入的订单数据需要回滚,分布式事务实现复杂且性能差。

二、异步事件驱动的优势 ​

事件驱动架构将"请求-响应"模式改为"发布-订阅"模式:

mermaid
graph LR
    A[订单服务] -->|发布 OrderCreated| B[(消息队列)]
    B -->|订阅| C[库存服务]
    B -->|订阅| D[支付服务]
    B -->|订阅| E[通知服务]

解耦。发布者无需知道消费者是谁,消费者可以动态增减。新增一个数据分析服务只需订阅相应 topic,不影响现有服务。

弹性。消费者临时宕机不影响发布者。消息在队列中持久化,消费者恢复后继续处理。配合重试机制,可以优雅处理瞬时故障。

可扩展。同一服务的多个实例可以加入同一个消费者组(Consumer Group),消息自动分片,实现水平扩展而无需额外负载均衡组件。

三、Watermill 的定位 ​

Watermill 是 Go 语言的事件驱动框架,核心理念是 "Event-driven applications the easy way in Go"。它提供了一套统一的 Pub/Sub 抽象,让开发者用相同的 API 编写业务逻辑,底层消息传输实现可自由切换。

go
// 发布消息 —— 所有 Pub/Sub 后端统一接口
pub.Publish("order.created", msg)

// 订阅消息 —— 返回 channel,配合 Router 自动消费
messages, _ := sub.Subscribe(ctx, "order.created")

四、与其他方案对比 ​

方案优点缺点
裸 Kafka SDK (sarama)性能极致,配置灵活代码量大,缺少重试/路由等通用能力
NATS Go Client简单轻量绑死 NATS,无法切换
Watermill统一抽象,多后端可互换,内置路由/中间件/CQRS有一层抽象开销(通常可忽略)

Watermill 的价值在于:编写业务逻辑时面对的是 message.Publisher 和 message.Subscriber 接口,而非具体的 Kafka/NATS/RabbitMQ SDK。单元测试用进程内 GoChannel(零依赖、零配置),生产环境只需切换底层实现——一行代码改 Kafka 为 NATS。

五、本项目学习路径 ​

本项目的 basic/ 目录包含 5 个独立可运行的示例(GoChannel 零依赖)。ecommerce/ 目录是一个基于 Kafka 的完整电商事件驱动系统,演示 Saga 分布式事务、顺序消费、可靠投递等实战模式。

建议阅读顺序:基础篇(本文档 01-06)→ 实战篇(07-13)→ 进阶篇(14-20)→ 扩展篇(21-23)。