找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2262

积分

0

好友

324

主题
发表于 昨天 05:11 | 查看: 5| 回复: 0

实现一个“消息系统”,方式有很多,每种方式都有它自己的适用边界。就像我们在设计项目时,从最初的事件 Hook,到三层架构、六边形架构,再到 DDD,每一步选择的背后都是边界和责任的考量。

在做项目时,选择哪种消息系统,不是为了给项目增加负担,而是要在正确的边界上,用对的方式,既保证功能,又保持系统轻量和可维护性。

很多朋友,只要一提到“消息系统”,Kafka 几乎成了默认答案。它高吞吐、生态成熟、社区活跃,看起来无可替代。

但当你真正把 Kafka 引入到一个 Golang 微服务项目 中,用上一段时间之后,往往会产生一个不太好意思说出口的感受:

Kafka 很强,但我们真的用到它的“强”了吗?

为了一个服务解耦、一次异步通知、几个内部事件,引入一整套 Kafka 集群、Topic 规划、Consumer Group 和 Offset 管理,成本并不低,而收益却并不总是匹配。很多团队还会考虑 RabbitMQ,但它在 Go 微服务内部通信场景下,同样会带来额外复杂度。

也正是在这样的背景下,我开始在多个 Go 项目中尝试使用 NATS。这篇文章,不是站队,也不是拉踩,而是一次 真实使用体验的复盘

一、问题不在 Kafka,而在使用场景

先说结论:Kafka 没有问题,用错地方才是问题。

在很多 Golang 项目中,Kafka 常被用在下面这些场景:

  • 微服务之间解耦
  • 订单创建后的异步处理
  • 内部事件广播
  • 控制面通知

但这些场景,本质需求只有三个:

  1. 解耦
  2. 异步
  3. 稳定

而 Kafka 的核心优势是什么?

  • 超高吞吐
  • 顺序写磁盘
  • 大规模数据流处理

你会发现一个明显的不匹配:
我们想要的是“通信能力”,却背上了“数据管道系统”的重量。

在 Go 微服务中,这种“重”体现在:

  • 部署和运维成本高
  • 开发阶段心智负担大
  • 本地调试和测试成本高
  • 对延迟并不友好

Kafka 很强,但并不是每一次异步都值得它出场。

顺带提一句,RabbitMQ 在企业级系统中也很常见,它擅长解决 业务异步和消息可靠投递 ,拥有 Exchange、Queue、Binding 等概念。但在 Golang 微服务内部通信场景下,这些能力并不会真正用上,反而增加了开发和运维复杂度。

二、我是为什么开始尝试 NATS 的

第一次接触 NATS,并不是因为它“新”,而是因为它 刚好补上了 Kafka 没覆盖好的那一段空档

当时我的诉求非常简单:

  • 服务之间能不能不用 HTTP 强耦合?
  • 能不能有一种“像 RPC,但更松散”的通信方式?
  • 能不能不用为此维护一套复杂的消息基础设施?

NATS 给我的第一感受只有一句话:

它不像一个“消息中间件”,更像是分布式系统里的通信底座。

没有复杂的概念,没有厚重的配置,Pub/Sub、Request/Reply 几乎开箱即用。对 Go 开发者来说,这种体验非常自然。

三、一个真实场景:订单系统的解耦实践

这是一个非常典型、也非常现实的业务场景。

1. 改造前:同步调用的“链式反应”

订单创建后,需要做这些事情:

  • 扣减库存
  • 发送通知
  • 风控校验
  • 更新推荐系统

最初的实现方式通常是:

Order  Service
 ├── Inventory Service
 ├── Notify Service
 ├── Risk Service
 └── Recommend Service

问题很快出现:

  • 任一服务变慢,订单接口就变慢
  • 任一服务失败,主流程就失败
  • 新增一个下游改一堆代码

2. Kafka 方案:解耦了,但有点“重”

后来我们用 Kafka 做异步解耦,逻辑上没问题,但很快暴露出新的现实问题:

  • Topic 设计成本高
  • 消费者组管理复杂
  • 运维成本不低
  • 对于内部事件,显得有些“大材小用”

3. NATS 方案:事件驱动真正落地

最终的方案非常简单:
订单服务只做一件事:发布事件。

nc.Publish("order.created", data)

下游服务各自订阅:

nc.Subscribe("order.created", handler)

改造后的效果非常直接:

  • 订单接口响应时间明显下降
  • 下游服务完全解耦
  • 新业务接入只需新增订阅者

这一次,我们真正感受到了“事件驱动架构”的轻量感。

四、NATS 真正好用的地方,不在概念里

很多文章会花大量篇幅介绍 NATS 的架构,但在实战中,真正频繁用到的只有三点:

1. Pub / Sub:天然适合内部事件

Subject 天然支持通配符,非常贴合业务语义:

order.created
order.paid
order.canceled

2. Request / Reply:被严重低估的能力

这是 NATS 在 Go 项目中 极具杀伤力 的一点。

msg, _ := nc.Request("user.query", data, time.Second)

你可以:

  • 像 RPC 一样调用
  • 又不绑定具体服务实例
  • 保留异步系统的弹性
    在内部系统中,这种模式比 HTTP + JSON 舒服得多。

3. JetStream:只在“该重的时候重”

当你真的需要:

  • 消息持久化
  • 至少一次投递
  • 消费确认
  • 消息回放
    再引入 JetStream,而不是一开始就上重武器。

五、说清楚边界:NATS 不是 Kafka 的替代品

这是必须讲清楚的一点。
如果你的需求是:

  • 日志收集
  • 数据分析
  • 海量数据流处理
  • 离线计算
    那么 Kafka 依然是正确选择。

一句话总结边界:

NATS 解决的是“服务之间怎么说话”,Kafka 解决的是“数据怎么流动”。

如果你用 NATS 去做 Kafka 的事情,迟早会踩坑;反过来,用 Kafka 去做服务通信,也会感到笨重。

六、Golang 项目里的消息系统选型建议

如果你只记住这一节,就够了。

  • 微服务内部通信 → NATS
  • 业务事件驱动 → NATS
  • 关键链路、强可靠 → NATS + JetStream
  • 数据管道、日志系统 → Kafka
  • 企业消息异步 / 复杂路由 → RabbitMQ

不要问“哪个更高级”,只问 哪个更合适

七、写在最后:真正的成熟,是不过度设计

回头看这些年的系统演进,我越来越确信一件事:

好的架构,不是堆出来的,而是克制出来的。

Kafka 依然很强,RabbitMQ 依然稳妥,也依然重要;但在 Golang 微服务的世界里,NATS 往往更贴合工程直觉。
工具不是信仰,选型才是能力。

希望这篇基于真实项目体验的分享,能为你下一个 Go 微服务的技术选型带来一些启发。更多关于架构设计和 Go 实践的深入讨论,欢迎在云栈社区交流。




上一篇:Burp Suite 测试双因子认证漏洞:通过设置验证码为0绕过机制剖析
下一篇:C++11/17/20 future库:更优雅的异步编程与高并发工具
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-16 02:06 , Processed in 0.321845 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表