裸调nats.connect默认不重试、无超时、不验健康,易因网络抖动断连;需显式配置重连策略、tls凭证、jetstream初始化、流创建及去重/顺序控制参数。

裸调 nats.Connect(nats.DefaultURL) 在本地能跑通,但一上生产就断连不恢复、消息乱序、消费者收不到历史数据——这不是 NATS 有问题,是客户端配置和用法没对齐服务端能力。
怎么连上 NATS 服务器又不被网络抖动搞崩
默认连接不重试、不设超时、不验健康,一次抖动就卡死或静默断开。必须显式加策略:
-
nats.MaxReconnects(60):别用 -1(无限重连),容易压垮服务端 -
nats.ReconnectWait(2 * time.Second):固定间隔太生硬,配合 jitter 更稳 -
nats.ReconnectJitter(100*time.Millisecond, time.Second):避免所有实例同一时刻重连 - 密码别写在 URL 里,改用
nats.UserCredentials("user.creds")加载凭证文件 - 启用了 TLS?URL 必须用
tls://前缀,且服务端证书要可信,否则Connect()会卡住不报错
JetStream 初始化必须在启动阶段完成,不能等 publish 时才触发
js.Publish() 第一次 panic 不是代码写错,是 jetstream.Context 根本没初始化。NATS 客户端不会自动准备 JetStream 能力。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 连接成功后立刻执行:
js, err := jetstream.New(nc),并检查err - 建议加健康检查:调
js.AccountInfo()确认上下文可用,失败则提前退出 - 流(Stream)创建是一次性动作,改配置得删了重建,不是热更新
消息“不丢”不是默认行为,得靠 JetStream + 正确的 Stream 配置
纯 NATS 是内存转发,消费者掉线期间的消息直接丢弃——这是设计,不是 bug。想持久化,三件事缺一不可:
- 启用 JetStream 后,必须调
js.AddStream()显式创建流,光连上没用 -
RetentionPolicy得选对:jetstream.InterestPolicy(只存活跃订阅者需要的)或jetstream.WorkQueuePolicy(每条只投一次) - 订阅时用
nats.DeliverPolicy(nats.DeliverAll)才能从头消费;默认行为是跳过已有消息 - 加
nats.Durable("processor-name")才能记住消费位置,否则每次都是全新 offset
去重和顺序不是 JetStream 自动保证的,关键控制权在客户端手里
开了 JetStream ≠ 天然幂等、天然有序。重复扣款、状态乱序,八成是没按规范发消息。
- 去重要生效,发布时必须带
nats.WithMsgID("order-12345"),ID 必须是业务唯一标识(如 order_id),不是uuid.New() - 流配置里的
Duplicates: 2*time.Minute是去重窗口,不是保留时间;若处理耗时超 2 分钟,重复仍会发生 - 多 goroutine 并发
js.Publish()到同一 subject,消息可能乱序;顺序敏感场景应串行发布,或用单 goroutine + channel 缓冲 - NATS 只保证 at-least-once,消费者必须自己做幂等:比如用
order_id查数据库唯一索引,或 Redis SETNX 拦截
最容易被忽略的是:JetStream 的流定义、发布方式、订阅策略三者必须严格对齐,差一个参数,表现就是“消息丢了”或“重复了”,但错误日志里往往没线索。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










