jetstream非自动启用,须显式启用服务端、调用nc.jetstream()初始化、addstream创建流、选对retentionpolicy和storage类型,并配置deliverpolicy与durable才能持久化。

JetStream 不是连上 NATS 就自动可用的持久化功能,它必须显式启用、显式建流、显式配置存储策略——跳过任一环,消息就真会丢。
JetStream 连接必须在 nats.Connect() 后立刻初始化
很多人调用 nats.Connect() 成功后,直接在业务逻辑里用 js.Publish(),结果 panic 报错:JetStream not enabled on server 或 nil pointer dereference。这不是客户端 bug,而是 JetStream 模块根本没启用,或客户端没做初始化检查。
- 必须在
nats.Connect()返回非 nil*nats.Conn后,**立即**调用nc.JetStream()(或jetstream.New(nc)),并检查返回的error - 不能等到第一次
Publish或Subscribe时才触发——那时错误已深埋在业务调用栈里,日志难定位 - 生产环境还要配凭证和重连:
nats.UserCredentials("user.creds")、nats.MaxReconnects(60)、nats.ReconnectJitter(100*time.Millisecond, time.Second)
不手动创建 Stream,NATS 默认不存任何消息
裸调 nc.Publish("orders.created", data),消费者掉线 5 秒再上线,之前的消息就彻底消失。这不是配置问题,是 NATS 核心设计:纯 Pub/Sub 是无状态的,**不建 Stream = 不持久化 = 消息即发即焚**。
- 必须提前调
js.AddStream(&jetstream.StreamConfig{...})显式声明流 -
RetentionPolicy很关键:jetstream.InterestPolicy只保留当前有活跃消费者关心的消息,比默认的LimitsPolicy更省空间;但所有消费者都下线时,消息也会被清空 - 开发验证可用
Storage: jetstream.MemoryStorage加速调试,但务必记住:内存流在服务器重启后全丢,不可用于生产关键数据
消费者收不到历史消息?大概率是 DeliverPolicy 设错了
订阅后只收到新消息,而流里明明有几百条旧数据——这几乎可以断定是 DeliverPolicy 配置问题。JetStream 默认行为就是跳过已有消息,不是“自动回溯”。
- 想从头消费:用
jetstream.DeliverAllPolicy - 想从最新开始:用
jetstream.DeliverLastPolicy(注意不是默认值,得显式设) - 想按时间点重放:用
jetstream.DeliverByStartTimePolicy+OptStartTime(time.Now().Add(-24*time.Hour)) - 若用
jetstream.DeliverLastPerSubjectPolicy,则每个 subject 只取最后一条,适合状态同步场景
FileStorage 和 MemoryStorage 的选择直接影响可靠性边界
两种存储类型不是性能高低之分,而是可靠性边界的划分。选错类型,等于主动放弃某类故障下的数据保障。
-
jetstream.FileStorage:消息落盘,服务重启不丢,支持多副本(Replicas: 3),适用于订单、翻译请求等业务关键数据 -
jetstream.MemoryStorage:仅驻留内存,节点宕机或重启即清空,且不支持集群复制,只适合 metrics、trace 等临时中间数据 - 两者在代码中通过
Storage字段切换,但底层实现完全隔离——FileStorage使用分块日志(block-based WAL),MemoryStorage是纯内存哈希表,无法混用或热切换
最容易被忽略的一点:JetStream 的流(Stream)和消费者(Consumer)是两个独立生命周期的对象。删 Stream 会清空所有消息;删 Consumer 只是移除其消费位点,不影响流内数据。很多线上事故,其实是误删了 Consumer 却以为“重置了流”,结果发现历史消息还在,只是位点丢了——这时候得靠 DeliverPolicy 重新拉取,而不是重建流。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











