NATS и JetStream в production
Зачем знать. NATS — лёгкая, быстрая и простая в эксплуатации messaging-система; JetStream добавляет персистентность и стримы. Часто встречается в Cloud Native и edge архитектурах (CNCF graduated, 2018). Middle 2 Go-инженер должен уметь выбрать между NATS / Kafka / RabbitMQ, настроить cluster + JetStream, реализовать durable consumers, KV-store, mirror streams и понимать гарантии доставки.
Содержание
Заголовок раздела «Содержание»- Концепция: NATS Core и JetStream
- Production-практики
- Gotchas
- Real cases: Synadia, Walmart, Mastercard
- 25 вопросов
- Practice
- Источники
1. Концепция (кратко)
Заголовок раздела «1. Концепция (кратко)»1.1 NATS Core — fundamentals
Заголовок раздела «1.1 NATS Core — fundamentals»NATS — pub/sub бус без персистентности (in-memory), миллионы сообщений/сек, sub-ms latency.
┌─────────┐ publish "orders.created" ┌─────────┐ │Publisher│ ──────────────────────────▶│ NATS │ └─────────┘ │ server │ └────┬────┘ subscribe "orders.*" │ ▼ ┌──────────┐ │Subscriber│ └──────────┘Subjects — иерархические темы через точку: orders.us.created, metrics.cpu.high.
Wildcards:
*— один уровень:orders.*.createdmatchesorders.us.created, не matchesorders.us.created.v2.>— все уровни от текущего:orders.>matchesorders.us.created.v2.
Queue groups — load balancing внутри группы subscriber’ов:
publish ─▶ orders.created ─┬─▶ worker-1 (queue "workers") ┐ └─▶ worker-2 (queue "workers") ┘ один из них получит └─▶ logger (без queue group) ← получит всегдаRequest-Reply — встроенный pattern (RPC поверх pub/sub): publisher отправляет message на subject + inbox-subject для ответа.
msg, err := nc.Request("calc.add", []byte(`{"a":1,"b":2}`), time.Second)NATS Core не хранит сообщения: если subscriber offline — он пропустил.
1.2 JetStream — персистентность
Заголовок раздела «1.2 JetStream — персистентность»JetStream добавляет персистентный стрим поверх subjects, по сути это log с retention + durable consumers + replication.
┌─────────────────────────────────────────────────┐ │ JetStream cluster (3 nodes, RAFT) │ │ │ │ Stream "ORDERS" (subjects: orders.>) │ │ ┌──────────────────────────────────────────┐ │ │ │ msg1 msg2 msg3 ... msgN │ │ │ └──────────────────────────────────────────┘ │ │ │ │ │ │ ▼ ▼ │ │ Consumer "billing" Consumer "shipping" │ │ (durable, ack) (durable, ack) │ └─────────────────────────────────────────────────┘Сущности:
- Stream — persistent set сообщений с заданным subject filter (
orders.>). - Consumer — позиция чтения + полиси acknowledgement. Бывают push (server пушит сообщения) и pull (клиент сам pull в нужном темпе). Durable имя сохраняется при reconnect, ephemeral — удаляется по таймауту.
Acks:
AckExplicit(default для durable) — нужен явный ack за каждое сообщение.AckNone— не нужны (fire-and-forget).AckAll— ack одного сообщения = ack всех предыдущих.Nak()— negative ack, redeliver.InProgress()— обновить таймерAckWait, ещё работаем.Term()— terminate: больше не пытайся, удали (не отправляй в DLQ-стрим).
Retention policies для stream:
LimitsPolicy(default) — хранить пока в пределах лимитов (MaxBytes,MaxAge,MaxMsgs).WorkQueuePolicy— удаляем сообщение как только оно прочитано хоть одним consumer (queue semantics; max 1 consumer на subject в этом stream).InterestPolicy— хранить пока есть consumer, заинтересованный в этом сообщении.
Storage:
FileStorage— файловое, persist через restart.MemoryStorage— RAM-only, теряется при restart, но быстрое.
Replication: Replicas=3 — данные на 3 узлах через RAFT (NATS использует JetStream RAFT для consensus).
Server-side filtering: FilterSubject на consumer — стрим может содержать orders.>, а consumer читать только orders.us.>.
1.3 KV bucket и Object store
Заголовок раздела «1.3 KV bucket и Object store»KV (Key-Value) — поверх JetStream stream с compaction:
bucket "user-prefs" ─ key "user.42.theme" ──▶ "dark" ─ key "user.42.locale" ──▶ "ru"API: Get/Put/Delete + Watch (subscribe на изменения) + History (последние N значений).
Object Store — для blob (файлы, > 8 MB):
bucket "uploads" ─ object "report.pdf" (chunked, metadata)1.4 Mirror streams
Заголовок раздела «1.4 Mirror streams»Mirror — read-only копия stream в другом cluster / на другом server. Используется для:
- Geo-replication (DR copy в другом регионе).
- Read scaling (mirror ближе к читателю).
Source — стрим может пополняться сообщениями из других стримов (mux нескольких stream в один).
1.5 Leaf nodes — edge
Заголовок раздела «1.5 Leaf nodes — edge»Leaf node — NATS-server, который подключается к hub-кластеру как «edge-узел». Локальные клиенты работают через leaf, hub видит leaf как обычный subscriber.
┌──────────────────────┐ │ HUB cluster (cloud) │ └──────────┬───────────┘ │ leaf-connect ┌──────────▼───────────┐ ┌──────────────────────┐ │ Leaf node (edge) │ │ Leaf node (edge) │ │ Factory robot │ │ Branch office │ └──────────────────────┘ └──────────────────────┘Subject пространство склеивается, JetStream может быть и на leaf, и на hub.
1.6 Cluster topology
Заголовок раздела «1.6 Cluster topology»- Cluster — 3+ NATS-серверов, гошшипят, обеспечивают HA.
- Gateway — connection между cluster’ами (для гео-распределённой архитектуры).
- Super-cluster — несколько cluster’ов соединены через gateways. Subject-пространство глобально, маршрутизация автоматическая.
┌──────────────┐ gateway ┌──────────────┐ │ Cluster US │──────────▶│ Cluster EU │ │ 3 servers │◀──────────│ 3 servers │ └──────────────┘ └──────────────┘1.7 NATS vs Kafka vs RabbitMQ (краткий снимок)
Заголовок раздела «1.7 NATS vs Kafka vs RabbitMQ (краткий снимок)»| NATS | NATS JetStream | Kafka | RabbitMQ | |
|---|---|---|---|---|
| Persistence | нет | да | да | да |
| Throughput | очень высокий | высокий | очень высокий | средний |
| Latency | sub-ms | ~ms | ~ms-10ms | ms |
| Ops | очень простой | простой | сложный | средний |
| Single binary | да | да | нет (JVM) | нет (Erlang) |
| Ecosystem | растущий | растущий | огромный | большой |
| Use case | RPC, real-time | streams, KV | data pipelines, EoS | flexible routing |
2. Production-практики
Заголовок раздела «2. Production-практики»2.1 Подключение и опции (nats.go)
Заголовок раздела «2.1 Подключение и опции (nats.go)»import "github.com/nats-io/nats.go"
nc, err := nats.Connect( "nats://n1:4222,nats://n2:4222,nats://n3:4222", nats.Name("orders-service"), nats.MaxReconnects(-1), // бесконечно nats.ReconnectWait(2*time.Second), nats.PingInterval(20*time.Second), nats.MaxPingsOutstanding(5), nats.ReconnectBufSize(8*1024*1024), // буфер на время disconnect nats.ErrorHandler(func(_ *nats.Conn, sub *nats.Subscription, err error) { log.Errorw("nats error", "sub", sub.Subject, "err", err) }), nats.DisconnectErrHandler(func(_ *nats.Conn, err error) { log.Warnw("disconnected", "err", err) }), nats.ReconnectHandler(func(c *nats.Conn) { log.Infow("reconnected", "url", c.ConnectedUrl()) }), nats.UserCredentials("./user.creds"), // для NATS 2.0+ accounts/JWT nats.RootCAs("./ca.pem"),)2.2 NATS Core: pub/sub, queue group, request-reply
Заголовок раздела «2.2 NATS Core: pub/sub, queue group, request-reply»// publishnc.Publish("orders.created", payload)
// subscribesub, _ := nc.Subscribe("orders.*", func(m *nats.Msg) { process(m.Data)})defer sub.Unsubscribe()
// queue group (load balancing)nc.QueueSubscribe("orders.created", "workers", func(m *nats.Msg) { ... })
// request-replymsg, err := nc.Request("calc.add", body, 2*time.Second)2.3 JetStream: создание stream
Заголовок раздела «2.3 JetStream: создание stream»js, err := nc.JetStream(nats.PublishAsyncMaxPending(256))
_, err = js.AddStream(&nats.StreamConfig{ Name: "ORDERS", Subjects: []string{"orders.>"}, Storage: nats.FileStorage, Replicas: 3, Retention: nats.LimitsPolicy, MaxAge: 7 * 24 * time.Hour, MaxBytes: 100 << 30, // 100 GB Discard: nats.DiscardOld, Duplicates: 2 * time.Minute, // окно дедупликации})2.4 JetStream: publish с дедупликацией
Заголовок раздела «2.4 JetStream: publish с дедупликацией»ack, err := js.Publish("orders.us.created", payload, nats.MsgId(orderID), // дедупликация в окне Duplicates nats.AckWait(5*time.Second),)log.Infow("published", "stream", ack.Stream, "seq", ack.Sequence)⚠️ NATS дедуплицирует по Nats-Msg-Id в окне Duplicates (default 2 минуты). Этого достаточно для retry, но не «вечная» дедупликация.
2.5 JetStream consumers: pull vs push
Заголовок раздела «2.5 JetStream consumers: pull vs push»Pull (предпочтительно для backend):
sub, _ := js.PullSubscribe("orders.>", "billing", nats.AckExplicit(), nats.MaxDeliver(5), nats.AckWait(30*time.Second),)
for { msgs, err := sub.Fetch(100, nats.MaxWait(5*time.Second)) if errors.Is(err, nats.ErrTimeout) { continue } for _, m := range msgs { if err := process(m.Data); err != nil { m.NakWithDelay(30 * time.Second) // retry через 30 секунд continue } m.Ack() }}Push (server пушит, мы реагируем):
sub, _ := js.Subscribe("orders.>", func(m *nats.Msg) { if err := process(m.Data); err != nil { m.Nak() return } m.Ack()}, nats.Durable("billing"), nats.ManualAck())2.6 Server-side filtering
Заголовок раздела «2.6 Server-side filtering»js.AddConsumer("ORDERS", &nats.ConsumerConfig{ Durable: "us-billing", FilterSubject: "orders.us.>", // только US AckPolicy: nats.AckExplicitPolicy, DeliverPolicy: nats.DeliverAllPolicy,})Network экономия: сообщения не из orders.us.> даже не отправляются на consumer.
2.7 KV bucket
Заголовок раздела «2.7 KV bucket»kv, err := js.CreateKeyValue(&nats.KeyValueConfig{ Bucket: "user-prefs", History: 5, // последние 5 значений Storage: nats.FileStorage, Replicas: 3,})
kv.Put("user.42.theme", []byte("dark"))entry, _ := kv.Get("user.42.theme")
// Watch (live-stream изменений)w, _ := kv.WatchAll()for upd := range w.Updates() { if upd == nil { continue } // конец initial state log.Infow("changed", "key", upd.Key(), "value", string(upd.Value()))}KV — отличная альтернатива Redis для feature flags, конфигов, distributed locks.
2.8 Object store
Заголовок раздела «2.8 Object store»obs, _ := js.CreateObjectStore(&nats.ObjectStoreConfig{ Bucket: "uploads", Storage: nats.FileStorage, Replicas: 3,})
obs.PutFile("report.pdf")obs.GetFile("report.pdf", "/tmp/report.pdf")2.9 Mirror и source
Заголовок раздела «2.9 Mirror и source»js.AddStream(&nats.StreamConfig{ Name: "ORDERS_MIRROR_EU", Mirror: &nats.StreamSource{ Name: "ORDERS", FilterSubject: "orders.eu.>", External: &nats.ExternalStream{ APIPrefix: "$JS.us.API", DeliverPrefix: "deliver.us", }, }, Replicas: 3,})2.10 Cluster setup
Заголовок раздела «2.10 Cluster setup»nats-server.conf (один из 3 узлов):
server_name: n1listen: 0.0.0.0:4222
cluster { name: prod listen: 0.0.0.0:6222 routes = [ nats://n1:6222 nats://n2:6222 nats://n3:6222 ]}
jetstream { store_dir: /var/lib/nats max_memory_store: 4G max_file_store: 200G}
http_port: 8222 # monitoring3-узловый cluster — минимум для JetStream RAFT (quorum ≥ 2).
2.11 Auth — accounts и JWT
Заголовок раздела «2.11 Auth — accounts и JWT»NATS 2.0+ имеет multi-tenant систему accounts: изоляция subject-пространства между приложениями, JWT-based authentication.
- Operator (root)
- Accounts (tenants)
- Users (внутри account, JWT-signed)
Утилита nsc создаёт и подписывает JWT.
В Go-клиенте:
nats.UserCredentials("./alice.creds")2.12 Monitoring
Заголовок раздела «2.12 Monitoring»- Встроенный HTTP monitoring на
:8222:/varz,/jsz?streams=true,/connz,/routez. - prometheus-nats-exporter — официальный Prometheus exporter.
- NATS surveyor — distributed monitoring.
- NATS CLI:
nats stream report,nats consumer info,nats pub,nats sub.
2.13 Сравнение Kafka и NATS — когда что выбрать
Заголовок раздела «2.13 Сравнение Kafka и NATS — когда что выбрать»Бери NATS / JetStream если:
- нужна простая ops: single binary, кластер из 3 узлов и поехали;
- нужны RPC / request-reply / live pub-sub;
- нужно edge / IoT (leaf nodes);
- размер сообщений малый-средний, объём не петабайты;
- хочется KV-store или object store в той же системе.
Бери Kafka если:
- нужен максимальный throughput / retention петабайты;
- нужен богатый ecosystem (Kafka Connect, Streams, ksqlDB, Schema Registry);
- нужен EoS read-process-write pattern;
- уже инвестировано в Kafka.
3. Gotchas
Заголовок раздела «3. Gotchas»⚠️ NATS Core ≠ persistent. Если subscriber offline — сообщение потеряно. Для durable — JetStream.
⚠️ JetStream дедупликация имеет окно Duplicates (default 2 мин). Сверх окна — дубли пройдут. Не путать с idempotence Kafka.
⚠️ AckWait слишком короткий → сообщение redelivered, ты обрабатываешь повторно. Стандарт 30s, и периодически вызывай m.InProgress() для длинных задач.
⚠️ Pull subscription Fetch блокирует. Делай nats.MaxWait и обрабатывай ErrTimeout как «нет сообщений сейчас».
⚠️ JetStream cluster < 3 узлов = нет HA. Quorum для RAFT = (N/2)+1. На 1-2 узлах работает, но при падении lost.
⚠️ Mirror stream — read-only. Publish напрямую в mirror невозможен.
⚠️ MaxAckPending (default 1000) ограничивает сколько unacked сообщений может быть «в работе» у consumer. Превышение → server перестаёт отдавать новые. Поднимай для batch-обработки.
⚠️ MaxDeliver=-1 = бесконечный redelivery; poison message может зациклиться. Ставь конечное значение + DLQ-стрим.
⚠️ DLQ в NATS делается через source stream или ручным publish; нет встроенного DLX как в RabbitMQ.
⚠️ Memory storage теряет данные при рестарте. Не используй для прод.
⚠️ WorkQueuePolicy + 2 consumer на одном subject = ошибка. Только один consumer на subject в work-queue stream.
⚠️ Subject хранятся в памяти на сервере (для роутинга). Миллионы уникальных subjects = memory pressure.
⚠️ Sticky connection. При nats://a,b,c клиент выбирает один сервер; reconnect — другой. Балансировка только при reconnect, не per-message.
⚠️ JWT-токены не expirable «вечно». Если оператор скомпрометирован — нужен rotate (новая chain trust).
⚠️ NATS использует Subject length ограничение 255, payload по умолчанию 1 MB (max_payload). Для блобов — Object Store.
⚠️ Конфликт версий между сервером и клиентом. Старый клиент может не понимать новых фич JetStream. Держи серверы свежие, клиенты в lockstep.
4. Real cases
Заголовок раздела «4. Real cases»4.1 Synadia (создатели NATS) — commercial cloud
Заголовок раздела «4.1 Synadia (создатели NATS) — commercial cloud»Synadia Cloud / NGS — managed NATS глобально, с decentralized auth (operators, accounts), используют JetStream для коммерческого SaaS. Доказывает что NATS масштабируется до глобального multi-tenant.
4.2 Walmart — edge architecture
Заголовок раздела «4.2 Walmart — edge architecture»Walmart использует NATS для интеграции магазинов (десятки тысяч точек): leaf nodes в каждом магазине, hub-cluster в дата-центрах. Архитектура «edge with central control plane»: команды и события идут через NATS.
4.3 Mastercard — real-time payments
Заголовок раздела «4.3 Mastercard — real-time payments»Mastercard использует NATS для микросервисной шины внутри платёжной обработки: высокая throughput, sub-ms latency для критических path. NATS Core (без JetStream) для быстрых внутренних RPC.
4.4 Стандартные сценарии
Заголовок раздела «4.4 Стандартные сценарии»- Microservices RPC: request-reply вместо REST/gRPC внутри cluster.
- Real-time UI: WebSocket-сервис подписывается на JetStream, пушит изменения в браузер.
- IoT/Edge: NATS как протокол для устройств (есть mqtt-мост, leaf nodes).
- Replacement Redis Pub/Sub + опционально KV-store.
5. Вопросы
Заголовок раздела «5. Вопросы»1. Что такое NATS? Лёгкая cloud-native messaging-система с pub/sub, request-reply, queue groups. Pure Go-сервер, single binary.
2. Чем NATS Core отличается от JetStream? Core — in-memory pub/sub без персистентности. JetStream — добавляет persistent streams, durable consumers, KV, Object Store.
3. Что такое subject в NATS?
Иерархическая тема через точку (orders.us.created); может фильтроваться wildcards * и >.
4. Что делает * и > в subject?
* — ровно один уровень; > — все уровни от текущего.
5. Что такое queue group? Группа subscriber’ов на один subject; сообщение получает только один член группы (load balancing).
6. Что такое request-reply в NATS? Built-in RPC pattern: client публикует на subject + указывает inbox-subject для ответа, server отвечает на inbox.
7. Что такое stream в JetStream? Persistent log сообщений с заданным subject filter, retention и replication.
8. Какие retention policies в JetStream?
LimitsPolicy— пока в пределах лимитов.WorkQueuePolicy— удаляется после ack.InterestPolicy— пока есть заинтересованный consumer.
9. Что такое consumer в JetStream? Позиция чтения в stream + ack policy; бывают push/pull и durable/ephemeral.
10. Pull vs push consumer?
Push — сервер сам шлёт сообщения (нужна обработка backpressure на клиенте). Pull — клиент сам Fetch(N), удобнее для batch.
11. Какие ack-методы у JetStream?
Ack, Nak, InProgress, Term, AckAll. Nak запускает redelivery, Term — окончательное прекращение.
12. Как сделать дедупликацию в JetStream?
Publish с Nats-Msg-Id header (или nats.MsgId(id) в Go) — сервер дедуплицирует в окне Duplicates.
13. Что такое FilterSubject у consumer? Server-side фильтр: stream хранит broad subjects, consumer читает узкий подмножество.
14. Что такое KV bucket? Key-Value store поверх JetStream stream с compaction; поддерживает Get/Put/Delete/Watch/History.
15. Что такое Object Store? Хранилище для крупных blob (файлы) поверх JetStream; данные чанкуются.
16. Что такое mirror stream? Read-only копия stream в другом cluster / на другом сервере; для DR/geo-replication.
17. Что такое leaf node? NATS-сервер на edge, подключённый к hub-cluster через leaf-connection; subject space склеивается.
18. Что такое gateway? Connection между cluster’ами в super-cluster; обеспечивает гео-распределение.
19. Минимум узлов для HA JetStream? 3 узла (RAFT quorum). На 1-2 — нет HA.
20. Какие основные параметры StreamConfig?
Subjects, Storage, Replicas, Retention, MaxAge, MaxBytes, Discard, Duplicates.
21. Какие основные параметры ConsumerConfig?
Durable, AckPolicy, AckWait, MaxDeliver, FilterSubject, DeliverPolicy, MaxAckPending.
22. Что такое accounts в NATS 2.0? Multi-tenant изоляция: subject-пространство, лимиты, JWT-auth разделены между accounts.
23. Когда выбрать NATS вместо Kafka? Если приоритет — простота ops, RPC/request-reply, edge, low-latency real-time messaging.
24. Когда Kafka выгоднее NATS? Очень высокая throughput, петабайтная retention, EoS read-process-write, богатый ecosystem (Connect, Streams, Schema Registry).
25. Как сделать DLQ в JetStream?
Конечный MaxDeliver + publish failed-message в отдельный DLQ-stream (вручную) + Term() исходного.
6. Practice
Заголовок раздела «6. Practice»-
NATS cluster local. Запусти 3-узловый NATS-кластер локально (docker-compose), включи JetStream, проверь репликацию через
nats stream report. -
Durable pull consumer. Реализуй Go-consumer на stream
ORDERS,MaxDeliver=5,AckWait=30s, при ошибке —NakWithDelay(30s). Покажи что после 5 попыток сообщение уйдёт в DLQ-стрим. -
KV для feature flags. Создай KV-bucket
flags, реализуй middleware который проверяет flag черезGet, и Watch-loop, чтобы обновлять in-memory cache. -
Request-reply microservice. Сервис
calcобрабатываетcalc.add/calc.mulчерезnc.Subscribe; клиент используетnc.Request. Замерь latency vs HTTP/gRPC. -
Mirror stream. Создай stream
ORDERSв одном cluster, mirrorORDERS_DRв другом; останови источник, проверь что mirror сохранил данные. -
Object store. Загрузи 100 MB файл в Object Store, скачай в другом процессе, проверь чанкование.
-
Leaf node. Подними leaf node, соедини с hub, опубликуй subject из leaf, прими в hub.
-
JetStream + outbox. Postgres outbox-таблица + Go-poller, публикует в JetStream с
Nats-Msg-Id= outbox-id; verify дедупликацию. -
Сравни throughput NATS Core vs JetStream vs Kafka на одном железе (1 KB payload, 4 producers, 4 consumers).
-
Prometheus monitoring. Подними prometheus-nats-exporter, дашборд в Grafana: stream lag, consumer pending, server CPU.
7. Дополнительные блоки
Заголовок раздела «7. Дополнительные блоки»7.1 ASCII: NATS super-cluster
Заголовок раздела «7.1 ASCII: NATS super-cluster» ┌───────────────────────────────────────────────────────────┐ │ SUPER-CLUSTER │ │ │ │ ┌──────────────┐ gateway ┌──────────────┐ │ │ │ Cluster US │◀──────────▶│ Cluster EU │ │ │ │ │ │ │ │ │ │ ┌──┬──┬──┐ │ │ ┌──┬──┬──┐ │ │ │ │ │n1│n2│n3│ │ │ │e1│e2│e3│ │ │ │ │ └──┴──┴──┘ │ │ └──┴──┴──┘ │ │ │ └──┬───────────┘ └──────────────┘ │ │ │ leaf-connect │ │ ▼ │ │ ┌──────────────┐ │ │ │ Leaf (edge) │ ← локальные клиенты ходят сюда │ │ │ store 1 │ │ │ └──────────────┘ │ └───────────────────────────────────────────────────────────┘7.2 Структура JetStream stream + consumer
Заголовок раздела «7.2 Структура JetStream stream + consumer»Stream "ORDERS"├── subjects: orders.>├── storage: file├── replicas: 3├── retention: limits├── max_age: 7d├── max_bytes: 100GB├── discard: old├── duplicate_window: 2m└── consumers: ├── "billing" (durable, pull, ack_explicit, max_deliver=5, filter=orders.us.>) ├── "shipping" (durable, push, ack_explicit, filter=orders.eu.>) └── "audit" (ephemeral, push, ack_none)7.3 Безопасный backoff при ack-loop
Заголовок раздела «7.3 Безопасный backoff при ack-loop»for { msgs, err := sub.Fetch(50, nats.MaxWait(2*time.Second)) if errors.Is(err, nats.ErrTimeout) { continue } if err != nil { log.Warnw("fetch failed", "err", err) time.Sleep(time.Second) // не спамим брокер continue } for _, m := range msgs { meta, _ := m.Metadata() if meta.NumDelivered > 5 { // poison message → DLQ stream + Term publishDLQ(m) m.Term() continue } if err := process(m.Data); err != nil { delay := time.Duration(meta.NumDelivered) * 10 * time.Second m.NakWithDelay(delay) continue } m.Ack() }}7.4 KV use cases
Заголовок раздела «7.4 KV use cases»- Feature flags:
kv.Put("flag.new_checkout", []byte("on"))+ Watch для live-обновлений. - Distributed lock:
kv.Create(key, value)атомарен (Create fails если ключ есть) — простой lock. - Session storage: TTL per-key (
History+MaxAge). - Service discovery: keys как
services.<name>.<instance>+ Watch для появления/исчезновения.
7.5 Bench-ориентиры (single-node, 3-broker cluster)
Заголовок раздела «7.5 Bench-ориентиры (single-node, 3-broker cluster)»| Сценарий | Throughput | Latency p99 |
|---|---|---|
| Core pub-sub, 256B | 7M msg/s | 0.5 ms |
| Core request-reply, 256B | 800k req/s | 1 ms |
| JetStream (file, RF=3), 1KB | 200k msg/s | 5-10 ms |
| JetStream (mem, RF=1), 1KB | 1M msg/s | 1-2 ms |
(данные ориентировочные, зависят от железа; сравни с Kafka где JetStream-prod аналог ~ Kafka producer perf, но с гораздо меньшим bootstrap).
7.6 Migration: from Kafka to NATS (когда стоит)
Заголовок раздела «7.6 Migration: from Kafka to NATS (когда стоит)»Кейс: команда платежей раньше пользовалась Kafka для микросервисной шины, перешла на NATS JetStream:
- Ops стала проще — single binary, 3 узла, без Zookeeper/KRaft.
- Удалось убрать RPC через REST → request-reply поверх NATS.
- Throughput не пострадал (объёмы не петабайты).
- Минус: пришлось заменить Kafka Connect-pipeline на собственный (NATS экосистема меньше).
7.7 nack vs term — когда что
Заголовок раздела «7.7 nack vs term — когда что»- Nak (или NakWithDelay) — временная ошибка: внешний сервис недоступен, retry поможет.
- Term — постоянная ошибка: payload corrupt, validation failed, нет смысла retry.
- Ack без обработки = потеря данных. Опасно для critical путей; делайте только когда уверены.
7.8 Чек-лист продакшен NATS-deployment
Заголовок раздела «7.8 Чек-лист продакшен NATS-deployment»- Cluster 3+ узлов с RAFT JetStream.
- JetStream storage на SSD/NVMe, отдельный диск.
-
max_memory_store,max_file_storeсконфигурированы. - Auth через accounts/JWT (не shared username/password).
- TLS на listen-port и cluster route.
- Streams с replicas=3, file storage.
- DLQ stream +
MaxDeliverконечный. - Prometheus monitoring + Grafana дашборд.
- Alerts: stream pending, server down, raft un-healthy.
- Backup:
nats stream backupregular. - Тестирование leaf node disconnect/reconnect.
7.9 Полезные nats-CLI команды
Заголовок раздела «7.9 Полезные nats-CLI команды»# Состояние сервераnats server check connectionnats server info
# Streamsnats stream lsnats stream info ORDERSnats stream reportnats stream backup ORDERS ./backup
# Consumersnats consumer ls ORDERSnats consumer info ORDERS billingnats consumer report ORDERS billing
# KVnats kv lsnats kv put flags new_checkout onnats kv watch flags
# Pub/subnats sub "orders.>"nats pub "orders.us.created" '{"id":1}'nats req "calc.add" '{"a":1,"b":2}'
# Контекст (multi-cluster)nats context save prod --server nats://prod:4222 --creds ./prod.credsnats context select prod7.10 Сравнение JetStream и Kafka на конкретных аспектах
Заголовок раздела «7.10 Сравнение JetStream и Kafka на конкретных аспектах»| Аспект | Kafka | JetStream |
|---|---|---|
| HA: replication | leader/followers ISR | RAFT |
| HA: failover | leader election | RAFT leader election |
| Дедупликация | по PID+seq внутри session | по Msg-Id в окне Duplicates |
| Retention | size / time | size / time / interest / work-queue |
| Filtering на сервере | partitions only | по subject filter (точечный) |
| KV / Object Store | внешние тулзы | встроено |
| Cross-cluster | MirrorMaker 2 | gateways / mirror streams |
| Single binary | нет (JVM) | да |
| Min cluster | 3 brokers | 3 servers |
8. Источники
Заголовок раздела «8. Источники»- NATS Documentation — официальная документация.
- JetStream design and architecture — глубокий разбор.
- nats-io/nats.go — Go-клиент.
- NATS by Example — рецепты, в т.ч. на Go.
- Synadia blog — статьи от создателей.
- Practical NATS — Waldemar Quevedo.
- CNCF: NATS case studies — Walmart, Mastercard и др.
- nats-server конфигурация — все параметры.
- Comparing Kafka, RabbitMQ, NATS (Confluent blog, обзоры 2024) — сравнение.
- prometheus-nats-exporter — мониторинг.