Blog

消息队列与NATs最小运行模型

1435597771 · Aug 4, 2026

本文从同步调用的问题出发,介绍 Core NATS 的最小发布订阅模型,包括Publisher、Subscriber、Subject 和 NATS Server,并通过异常场景解释其“至多一次”语义。 同步与异步 在开始之前,我们需要先了解一下,同步和异步的区别,为什么有同步和异步之分。 我们需要想象一下,在程序中有订单模块和积分模块。他们一个负责用户下订单,一个负责为用户增加积分。 同步:如果用户下单了,那么会调用订单模块的方法和积分模块的方法,订单模块需要等待被积分模块返回结果,才能继续执行。那么就是同步 异步:用户下单了,调用了订单模块,接着再调用积分模块,而是两个模块独立的运行,订单模块并不需要等待积分模块处理完成,就能执行自己的工作。那么就是异步 我们可以想象一下,同步会带来什么问题: 下单和增加积分存在业务关联,但积分通常属于下单成功后的附加处理,不应该成为下单接口成功返回的强依赖。如果同步那么积分模块发生错误,会让下订单也失败 用户下订单,必须要等到积分模块执行完才返回,那么可能会带来延迟。 所以,在最好的情况下,两个负责不同的功能,不应该耦合在一起,消息队列是解决这类问题的一种常见方案。它让发送方和处理方不必直接同步调用,从而实现异步处理并降低耦合。 消息中间件的最小模型 消息需要有消费者,和生产者,以及中间的服务商,也即是Publisher,Subscriber和Broker。 Publisher负责生产消息,SubScriber负责消费消息。那么为什么还需要Broker,因为如果没有Broker,Publisher就必须需要知道他应该给哪个Subscriber发送消息,而有了Broker,那么Publisher就只需要生产消息,并不需要关注谁消费了消息。同时Subscriber也只需要关注自己如何消费消息,Publisher与Subscriber彼此不再直接以来彼此 CoreNATS 在NATS这个消息队列中,我们先来了解CoreNATS这一个模式,CoreNATS是一个面向实时通信的消息路由系统,他解决了服务之间的同步依赖。他有几个核心概念需要了解一下: Subject:Subject 是消息的逻辑主题和路由地址。Publisher 向某个 Subject 发布,NATS Server 根据订阅关系,将消息转发给当前在线且匹配该 Subject 的 Subscriber。 Publisher:生产者,向Subject发送消息 Subscriber:消费者,订阅Subject,收到消息后会执行回调的方法或者服务 Broker:生产者和消费者的中间商,负责消息接收与路由的系统角色,NATSServer就是Broker 那么消息是如何传递的呢? 正常的流程如下: Publisher | | Publish(subject, data) v NATS Server | | 根据 Subject 匹配和实时转发 v Subscriber 回调 | | 执行业务方法 v 业务成功或失败 ⚠️: Publish() 返回 nil ,主要表示客户端接受了这次发布操作,没有发现即时错误。nats.go 客户端可能会缓冲待发送数据,因此短生命周期的 Publisher 通常会在退出前调用 Flush() 。 Flush() 会通过一次与 Server 的往返确认,确保此前的数据已经发送到 Server 并被处理到对应位置。但 Flush() 成功仍不能证明 Subscriber 已收到消息,更不能证明业务处理成功。 消息送达与业务成功 Core NATS 的普通发布订阅采用至多一次语义。对于某个 Subscriber,一条消息可能收到一次,也可能一次都收不到;Core NATS 不会因为 Subscriber 没收到或业务处理失败而自动持久化并重新投递。“可能收到,也可能收不到”看起来很简单,但它准确描述了 Core NATS 的可靠性边界:系统不会通过持久化和自动重投保证消息最终送达。 CoreNATS被设计用来异步调用功能,那么他的主要功能就是消息的转发,完成异步这一个动作。Core NATS 负责将消息实时路由给当前在线的匹配订阅者,但普通发布订阅不会跟踪订阅者的业务处理结果,也不会根据业务失败自动重投。 在最小实验中,消息要有机会被 Subscriber 收到,至少需要 NATS Server 可用、Subscriber 在发布时在线,并且双方的 Subject 匹配。 所以消息送达与业务成功是两回事 适用场景 我们知道了CoreNATS的至多一次的概念,那么因此他只适合符合下面特点的场景: 允许偶尔丢失的事件或消息 低延迟优先于历史补发的场景 他不适合: 消息必须保证送达 必须持久化消息 需要确认消费者业务处理成功,并在失败时自动重试。 业务处理失败需要消息系统重试 不应仅依赖 Core NATS 普通发布订阅承载不能丢失的资金和账务事件。