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.
- Создать stream: определить name + subjects-паттерны которые в него попадают
- Публиковать через `js.publish()` вместо `nc.publish()` - получаем sequence number и подтверждение записи
- Создать consumer с `AckPolicy.Explicit` для надёжной обработки
- Вызвать `msg.ack()` после успешной обработки или `msg.nak()` для retry
- Настроить `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-сервер - это упрощение или скрытый риск? В каком сценарии монолитный дизайн брокера может стать проблемой?