Транспорт бэкенда
NATS: облачный messaging нового поколения
Один NATS-сервер весит 10 МБ RAM. Один Kafka-брокер требует JVM + Zookeeper + минимум 4 ГБ heap. При этом NATS держит 10 миллионов сообщений в секунду против 1 миллиона у Kafka. Парадокс? Нет - просто два инструмента для разных задач.
- TikTok использует NATS для push-нотификаций на 1 млрд активных пользователей - latency < 50 мс в любую точку мира
- Synadia (создатели NATS) заменили весь внутренний messaging на JetStream, сократив инфраструктуру в 5 раз
- CloudFoundry использует NATS как основной message bus: тысячи микросервисов, миллионы сообщений в день без Kafka
Core NATS: fire-and-forget на 40 000 строк
NATS написан на Go. Весь сервер - 40 000 строк кода. Kafka - 700 000. Это не просто цифры: latency Core NATS составляет 30-50 мкс против 1-5 мс у Kafka. В 100 раз быстрее - не потому что магия, а потому что Core NATS не сохраняет сообщения вообще.
Модель предельно простая: publish/subscribe через subject-иерархию. Subject - это строка с точками: `orders.created`, `payments.completed`, `users.*.updated`. Звёздочка - один сегмент, `>` - всё дерево вниз. Подписчики регистрируются через паттерны - никаких топиков, никаких партиций.
Queue group - встроенный load balancing: N воркеров в одной группе получат каждое сообщение ровно один раз. Kafka делает это через consumer groups с партициями. NATS - без партиций, но и без гарантий доставки.
NATS-кластер работает по протоколу Raft для metadata. Сами сообщения не реплицируются в Core NATS - если подписчика нет в момент публикации, сообщение теряется. Это сознательный выбор: для IoT-телеметрии или real-time нотификаций потеря 0.1% пакетов приемлема, а latency критична.
CloudFoundry, Apcera, Synadia - продакшн-кейсы с миллионами сообщений в секунду на одном сервере. Vercel использует NATS для edge-координации. TikTok - для push-нотификаций на 1 млрд пользователей. При правильной настройке один NATS-сервер держит 10 млн сообщений/сек.
Чем Core NATS принципиально отличается от Kafka?
JetStream: персистентность поверх NATS
2021 год. Synadia выпускает JetStream - персистентный слой поверх Core NATS. Теперь NATS умеет то, что умеет Kafka: хранить сообщения, replay с любого offset, consumer groups с at-least-once гарантиями.
JetStream вводит два понятия: Stream и Consumer. Stream - именованное хранилище с retention-политикой (по времени, размеру, количеству). Consumer - позиция чтения в Stream. Один Stream, много Consumers - каждый читает независимо.
JetStream поддерживает два режима consumer: push (сервер отправляет сообщения) и pull (клиент запрашивает пакет). Pull-mode лучше для batch-обработки с rate control. Push-mode - для real-time pipeline. Kafka аналогично: poll() - это pull.
Репликация в JetStream конфигурируется на уровне Stream: `Replicas: 3`. NATS-кластер из 3 нод с Raft-консенсусом. Запись подтверждается после записи на quorum нод. Throughput JetStream - около 300 MB/s на запись, против 600-800 MB/s у Kafka. Компромисс: меньше throughput, но единая инфраструктура для messaging и streaming.
Что такое Consumer в JetStream?
Key-Value и Object Store поверх JetStream
NATS пошёл дальше messaging. KV Store - это JetStream Stream с Subject-нейминговой конвенцией `KV.bucket.key`. Получается persistent key-value store с TTL, revisions, watch. Это не Redis-конкурент - это distributed config store уровня etcd или Consul.
Object Store - тот же JetStream, но для хранения бинарных объектов. Chunk-based: файл делится на чанки по 128KB, каждый публикуется как отдельное сообщение. Получается S3-like API поверх NATS: Put, Get, Delete, List. Не замена S3 для больших данных, но удобно для ML-моделей весом до нескольких GB в Kubernetes-кластере.
KV Watch - это pub/sub поверх персистентности. При запуске watcher получает текущее состояние всех ключей (replay), затем - все изменения в реальном времени. Так реализуется service discovery: сервис пишет в KV при старте, умирает - TTL истекает, запись исчезает.
NATS KV Store реализован поверх...
Request-Reply: RPC поверх messaging
NATS имеет встроенный request-reply паттерн. Это не просто синтаксический сахар - это фундаментальная особенность протокола. Publisher отправляет сообщение с reply-subject (временный inbox). Subscriber отвечает на этот inbox. Publisher блокируется до получения ответа или timeout.
Scatter-gather - паттерн для aggregation. Один запрос уходит всем подписчикам (нет queue group), каждый отвечает на reply-subject. Клиент читает все ответы за фиксированное время. Так Netflix опрашивает состояние инстансов. Так Kubernetes health-checks работают через NATS в некоторых дистрибутивах.
Reply-subject генерируется как `_INBOX.{uuid}`. Это временный subject, существующий только в рамках одного запроса. NATS-сервер автоматически маршрутизирует ответ обратно к исходному клиенту даже в кластере.
Как реализован scatter-gather в NATS?
NATS vs Kafka: когда что выбирать
Kafka и NATS решают разные задачи. Путаница возникает потому, что с JetStream NATS стал streaming-системой. Но архитектурные различия остались фундаментальными.
Kafka выигрывает там, где нужна long-term retention (event sourcing, audit log), строгий ordering в рамках ключа, интеграция с Kafka Streams/ksqlDB, огромный consumer count при малом количестве partitions. NATS выигрывает там, где нужна минимальная latency, встроенный request-reply, легковесная инфраструктура, IoT/edge сценарии.
Hybrid-архитектура: Core NATS для real-time сигналов (цены, статусы, нотификации) + Kafka для event log и аналитики. Именно так устроены системы Apcera и многих fintech-компаний. NATS-сервер весит 10 MB RAM без JVM overhead.
NATS JetStream - это полноценная замена Kafka с лучшей производительностью
JetStream покрывает часть Kafka-сценариев, но не все - особенно при нужде в долгом retention и Kafka-экосистеме
Kafka имеет экосистему Kafka Connect, Kafka Streams, ksqlDB, Schema Registry. Это 10 лет разработки инструментов. JetStream - функциональный, но молодой. Выбор зависит от конкретных требований, не от общей быстроты
Какой сценарий лучше подходит для NATS, а не Kafka?
Связанные темы
NATS встраивается в более широкий ландшафт distributed messaging:
- Kafka — Основной конкурент в streaming-сценариях
- RabbitMQ — Альтернатива для task queue и routing
- Event-Driven Architecture — NATS JetStream - популярный backbone для EDA
- CAP-теорема — JetStream реализует конкретные CAP-выборы
Ключевые идеи
- Core NATS - fire-and-forget с latency 30-50 мкс, без персистентности, с встроенным request-reply
- JetStream добавляет персистентность, consumer groups и replay - конкурент Kafka для сценариев без долгого retention
- KV Store и Object Store - дополнительные примитивы поверх JetStream для config management и хранения артефактов
- Выбор NATS vs Kafka - не вопрос скорости, а вопрос экосистемы, retention-требований и операционной сложности
Вопросы для размышления
- Когда hybrid-архитектура NATS + Kafka имеет смысл, а когда она добавляет лишнюю сложность?
- Как JetStream Consumer Groups отличаются от Kafka Consumer Groups в плане ordering-гарантий?
- В каких сценариях NATS KV Store предпочтительнее etcd или Redis?
Связанные уроки
- bt-13-kafka — Kafka - основной конкурент, понимание необходимо
- bt-12-rabbitmq — RabbitMQ - альтернатива с другой моделью
- bt-17-event-driven — NATS JetStream - основа event-driven архитектур
- bt-16-redis-streams — Redis Streams - аналог для лёгкого messaging
- ds-02-cap-theorem — JetStream реализует конкретные CAP-трейдоффы
- net-55-message-queues