生产环境 NATS 连接必须显式配置重连策略、凭证加载和 JetStream 初始化;消息丢失主因是未启用 JetStream 或订阅策略错误;去重需客户端提供唯一 MsgID,顺序需单 goroutine 或业务序列号保障。

NATS 在 Go 里不是“连上就能用”,默认裸连(nats.Connect(nats.DefaultURL))只适合本地验证,生产环境不配重试、不加凭证、不启 JetStream,90% 的消息丢失和连接中断问题都源于此。
怎么连才不算裸连?
本地开发时 nats.Connect(nats.DefaultURL) 确实能发第一条消息,但生产环境网络抖动一来,连接断开后就卡死不动——因为默认 MaxReconnects 是 -1(无限重试),但重连间隔是 2 秒固定值,没抖动容忍机制。
- 必须显式配置重连策略:
nats.MaxReconnects(60)、nats.ReconnectWait(2*time.Second)、nats.ReconnectJitter(100*time.Millisecond, time.Second) - 密码别写在 URL 里:
"nats://user:pass@host:4222"是高危操作;改用nats.UserCredentials("user.creds")加载 NATS 官方凭证文件 - 如果服务端开了 JetStream,连接后立刻初始化:
js, err := nc.JetStream();别等js.Publish()时才调,否则首次调用可能 panic
为什么发了消息,订阅者收不到?
这是最常被误认为“NATS 坏了”的问题,实际几乎全是配置或模式误用:纯内存 Pub/Sub 模式下,消费者掉线期间发布的消息就是会丢——这不是 bug,是设计。
- 想“不丢”,必须启用 JetStream,并创建 Stream:
js.AddStream(&jetstream.StreamConfig{Subjects: []string{"orders.*"}, RetentionPolicy: jetstream.InterestPolicy}) - 订阅时要指定投递策略:
nats.DeliverPolicy(nats.DeliverAll)才能从头消费;用DeliverLastPerSubject重启后直接跳过中间事件 - 别依赖“自动补推”:JetStream 不会主动重发,得靠客户端自己管理 offset 或用
js.Subscribe(..., nats.Durable("my-durable"))绑定持久化订阅
JetStream 发布时重复/乱序怎么防?
JetStream 支持去重和有序,但全靠客户端配合。服务端不会替你生成 ID,也不会帮你串行发布。
立即学习“go语言免费学习笔记(深入)”;
- 每条消息必须带业务唯一 ID:
nats.WithMsgID("order-20260326-001");用uuid.New()生成的随机 ID 对去重无效 - 流配置里的
Duplicates: 2*time.Minute是去重窗口,不是保留时间;若单条消息处理耗时超 2 分钟,重复仍会发生 - 多 goroutine 并发调
js.Publish()同一 subject,顺序无法保证;关键顺序场景必须用单 goroutine + channel 缓冲,或按业务逻辑加序列号 + 服务端排序(需启用AllowDirect和客户端确认)
真正难的不是写通第一行 nc.Publish(),而是搞清“谁负责幂等”“谁决定重试”“谁保管消息生命周期”。NATS 把控制权交还给应用层,这既是性能来源,也是出错温床。


















