nats高可用集群必须同时满足jetstream启用、多节点拓扑可见、客户端连接策略适配三件事,缺一不可;否则看似集群实为单点故障。

直接上结论:NATS 高可用集群不是“搭完就稳”,而是必须同时满足三件事——JetStream 启用、多节点拓扑可见、客户端连接策略适配。缺一不可,否则看起来是集群,实际仍是单点故障。
JetStream 必须在连接后立即启用,不能等 publish 时才初始化
很多服务启动后能连上 NATS,但第一次 js.Publish() 就 panic,根本原因是 jetstream.New(nc) 被延迟调用。NATS 客户端本身不自动感知 JetStream 状态,nc.JetStream() 只是返回一个上下文包装器,不触发任何服务端检查。
- 必须在
nats.Connect()成功后立刻执行js, err := jetstream.New(nc),并检查err - 如果目标 Stream 尚未存在,别手动建——用
js.CreateStream()显式创建,并设jetstream.RetentionLimits和jetstream.Duplicates(2 * time.Minute) - 别复用同一个
*nats.Conn对象去反复调jetstream.New(),它不幂等;每个业务模块应持有独立的jetstream.Context
Docker Compose 部署三节点集群时,配置文件里漏掉 cluster 配置就白搭
只写 server_name 和 port 不足以组成集群。NATS 节点之间靠 cluster 块互相发现,且各节点的 routes 必须指向其他节点的 cluster 端口(默认 6222),不是客户端端口(4222)。
-
nats-1.conf里必须含:cluster { listen: "0.0.0.0:6222"; routes: ["nats://nats-2:6222", "nats://nats-3:6222"] } - 每个
container_name(如nats-1)必须在docker-compose.yml的extra_hosts或自定义网络中可被其他容器解析为 IP - 挂载的配置文件路径要一致,比如都用
/etc/nats/nats.conf,否则容器内读不到cluster配置
客户端连接字符串必须用逗号分隔多个 URL,且带重连参数
写成 "nats://nats-1:4222" 就等于只连第一个节点——哪怕它挂了,客户端也不会自动切到 nats-2。NATS 客户端不会主动探测集群拓扑,它只按你给的 URL 列表轮询。
- 生产环境连接串必须是:
"nats://nats-1:4222,nats://nats-2:4222,nats://nats-3:4222" - 必须加
nats.MaxReconnects(-1)(不是 0 或 10),否则连不上就放弃;配合nats.ReconnectWait(2 * time.Second)避免雪崩重试 - 单次连接超时要用
nats.Timeout(5 * time.Second),防止 DNS 卡住整个服务启动
消费端用 QueueSubscribe() 但没设 MaxInflight,等于没开并发
很多人以为用了 QueueSubscribe() 就自动负载均衡,结果压测发现 QPS 上不去。问题出在默认 nats.MaxInflight(1),所有消息仍被串行处理,只是换了个 goroutine。
- 必须显式设置
nats.MaxInflight(64)或更高(根据业务处理耗时和内存水位调) - 搭配
nats.AckWait(30 * time.Second)和nats.ManualAck(),否则消息发出去就丢 ACK,JetStream 会反复重投 - 同一
queue group下多个实例,必须确保它们订阅的是完全相同的 subject(如"orders.created"),多一个点或大小写都不行
最容易被忽略的点:JetStream 流(Stream)的 subjects 字段必须精确匹配发布时的 subject,通配符(如 "orders.*")在流定义里无效;而消费者订阅时才能用通配符。这个错配会导致消息进不了流,连日志都看不到痕迹。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











