Real-Time Backend

NATS / NATS JetStream

Kafka убивает скорость на edge. NATS доставляет за <1 мс - и Cloudflare это доказал.

  • Cloudflare использует NATS для маршрутизации событий между точками присутствия (PoP) - там где Kafka давал бы неприемлемые batch-задержки на latency-критичных путях
  • Synadia (создатели NATS) обслуживает системы с 50+ миллионами подключённых IoT-устройств через единый NATS-кластер с subject-based routing без конфигурации топиков
  • Стартапы переходят с RabbitMQ на NATS JetStream: один бинарник 20 МБ заменяет RabbitMQ + Erlang runtime + плагины, операционные расходы падают на порядок
  • В финтех-системах NATS используется для request-reply между микросервисами - встроенный паттерн позволяет делать синхронные вызовы поверх async брокера без дополнительных библиотек

NATS: минималистичный брокер

NATS - это open-source брокер сообщений, разработанный компанией Synadia. Его главный принцип: бинарник весит около 20 МБ, запускается за миллисекунды, потребляет минимум RAM. Задержка доставки сообщения - менее 1 мс при нагрузке тысяч публикаций в секунду. Это не урезанная версия Kafka - это принципиально другой класс инструмента: Kafka оптимизирован под максимальный throughput и персистентность, NATS - под минимальную latency и простоту операции.

Cloudflare использует NATS для edge-маршрутизации событий между точками присутствия (PoP). Когда запрос достигает PoP в Варшаве и нужно уведомить несколько внутренних сервисов - NATS доставляет это за субмиллисекундные интервалы, где Kafka создавал бы неприемлемые задержки из-за batch-логики.

  • Протокол поверх TCP - текстовый, human-readable, легко отлаживать через telnet
  • Pub/Sub без сохранения по умолчанию - fire-and-forget семантика
  • Один сервер обрабатывает 10-15 млн сообщений/сек на обычном железе
  • Кластеризация встроена: NATS создает mesh-кластер без внешнего координатора (в отличие от Kafka + Zookeeper)

Cloudflare выбрал NATS для edge-маршрутизации вместо Kafka. Какое свойство NATS стало определяющим?

Subject-based routing

В NATS нет понятия "топик" как в Kafka. Вместо этого - subjects: иерархические строки вида `orders.europe.paid`. Подписчик может слушать точный адрес, уровень через `*`, или всё поддерево через `>`. Это дает маршрутизацию без заранее объявленных топиков - достаточно просто опубликовать в нужный subject.

Queue groups в NATS - это аналог consumer groups в Kafka, но без необходимости настройки партиций. При горизонтальном масштабировании сервиса достаточно запустить новый инстанс с тем же queue group именем - NATS автоматически включит его в балансировку.

  • `*` - один уровень иерархии: `orders.*.paid` матчит `orders.europe.paid`, не матчит `orders.eu.west.paid`
  • `>` - один или более уровней: `orders.>` матчит всё начиная с `orders.`
  • Subject без wildcards - точное совпадение, наиболее эффективный вариант
  • Routing происходит в памяти брокера - никаких disk I/O для маршрутизации

Сервис обрабатывает платежи в нескольких регионах. Нужно слушать все события `payment.confirmed` независимо от региона: `payment.us.confirmed`, `payment.eu.confirmed`. Какой subject-паттерн использовать?

JetStream: персистентность поверх NATS

Базовый NATS - pure pub/sub без гарантий доставки: если подписчика нет в момент публикации, сообщение теряется. JetStream - встроенный persistence layer, который добавляет at-least-once доставку, replay с любой позиции, и потребительские курсоры - всё это без отдельного процесса, как расширение того же сервера NATS.

JetStream vs Kafka: Kafka хранит все события в append-only log и сам по себе является storage-first системой. JetStream - messaging-first с опциональной персистентностью. Kafka превосходит в throughput миллионов событий/сек и долгосрочном хранении (дни/недели). JetStream выигрывает по latency и простоте операции: нет Zookeeper, нет KRaft-кворума отдельно - JetStream встроен в тот же процесс NATS.

  1. Создать stream: определить name + subjects-паттерны которые в него попадают
  2. Публиковать через `js.publish()` вместо `nc.publish()` - получаем sequence number и подтверждение записи
  3. Создать consumer с `AckPolicy.Explicit` для надёжной обработки
  4. Вызвать `msg.ack()` после успешной обработки или `msg.nak()` для retry
  5. Настроить `max_deliver` и backoff-интервалы для управления retry-логикой

Сервис нотификаций публикует события в JetStream. При рестарте consumer-сервиса нужно гарантировать, что ни одно сообщение не потеряется. Какой механизм JetStream обеспечивает это?

NATS vs Redis Pub/Sub vs Kafka

Три инструмента часто сравнивают как взаимозаменяемые, но у каждого своя ниша. Redis Pub/Sub - примитивный broadcast без персистентности и без гарантий (подходит для invalidation кеша). NATS - быстрый routing с опциональной персистентностью через JetStream (подходит для микросервисов, IoT, edge). Kafka - storage-first платформа для event streaming, audit log, data pipelines с retention неделями и throughput миллионов/сек.

Synadia (компания за NATS) позиционирует NATS как "connectivity fabric" - единую сеть для всей инфраструктуры. Один кластер NATS может обслуживать IoT-устройства (edge), микросервисы (core) и data pipelines (JetStream) через изолированные accounts. Это снижает число брокеров, которыми нужно управлять.

  • Выбирать Redis Pub/Sub: cache invalidation, real-time presence, простые уведомления без гарантий
  • Выбирать NATS core: микросервисная коммуникация, request-reply паттерн, IoT telemetry
  • Выбирать JetStream: work queues, event sourcing в небольших системах, замена RabbitMQ
  • Выбирать Kafka: audit log, event streaming с долгим retention, data pipelines, throughput > 1M msg/sec

JetStream - это отдельный сервис, который нужно запускать рядом с NATS

JetStream встроен в тот же процесс nats-server и активируется флагом `-js` или конфигурацией

В отличие от Kafka, где KRaft или Zookeeper - отдельные процессы, JetStream является частью nats-server. Один бинарник с одним конфигурационным файлом запускает и messaging, и persistence layer.

Команда строит систему телеметрии для 50 000 IoT-устройств. Нужна доставка за < 2 мс, горизонтальное масштабирование и минимальная операционная сложность. Kafka уже есть в инфраструктуре для аналитики. Что выбрать для приёма телеметрии?

Итоги

  • NATS core - fire-and-forget pub/sub с latency < 1 мс, subject-based routing через wildcards `*` и `>`, queue groups для балансировки
  • JetStream добавляет at-least-once доставку и durable consumers поверх NATS без отдельного процесса - активируется флагом в том же nats-server
  • NATS выигрывает у Kafka по latency и операционной простоте, Kafka выигрывает по throughput и долгосрочному хранению - часто они используются вместе

Связанные темы

NATS вписывается в экосистему event-driven архитектуры рядом с другими брокерами и паттернами:

  • Apache Kafka — Альтернатива для высокого throughput и долгосрочного хранения событий
  • Redis Pub/Sub — Более простой аналог без персистентности, для cache invalidation и presence
  • Message Queue паттерны — JetStream реализует work queue и pub/sub паттерны из теории очередей сообщений

Вопросы для размышления

  • Если бы нужно было выбрать между NATS JetStream и Kafka для новой системы обработки платёжных событий - какие вопросы задать команде, чтобы сделать правильный выбор?
  • Как subject-based routing в NATS (`orders.eu.paid`) меняет подход к проектированию API между микросервисами по сравнению с Kafka-топиками?
  • JetStream встроен в NATS-сервер - это упрощение или скрытый риск? В каком сценарии монолитный дизайн брокера может стать проблемой?

Связанные уроки

  • net-55-message-queues
NATS / NATS JetStream

0

1

Войти