Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → NATS: брокер сообщений для микросервисов

NATS: лёгкий брокер сообщений, темы и JetStream

NATS: маршрутизация по темам с подстановочными знаками, отличие ядра NATS от JetStream, запрос-ответ, сохранение сообщений и сравнение с Kafka и RabbitMQ.

Прямой ответ

NATS — брокер сообщений с маршрутизацией по именованным темам. Его особенность — минимальная инфраструктура: один бинарный файл сервера без внешних зависимостей вроде системы хранения или координатора.

Маршрутизация строится на именах тем с поддержкой подстановочных знаков:

orders.created
orders.paid
orders.shipped

Подписка может охватывать группу тем:

orders.*          # все темы второго уровня
orders.>          # все темы, начинающиеся с orders

Подписка orders.> получает сообщения всех вложенных уровней, что позволяет сервису слушать всю группу событий без перечисления.

Ключевое различие внутри NATS — два режима работы.

Ядро NATS передаёт сообщение подписчикам, доступным в момент публикации. Если подписчик отключён, сообщение теряется. Это модель «не более одного раза», подходящая для уведомлений, где потеря приемлема.

JetStream добавляет сохранение сообщений:

Ядро NATS JetStream
Хранение сообщений Нет Есть
Подписчик отключён Сообщение теряется Сообщение ждёт
Гарантия доставки Не более одного раза Не менее одного раза
Повторное чтение Невозможно Возможно
Область применения Уведомления, обнаружение Потоки событий, очереди задач

Выбор режима определяется требованием к доставке; о гарантиях — в статье про надёжность доставки.

Отдельная возможность — запрос-ответ. Публикация с ожиданием ответа реализует вызов сервиса без знания его адреса:

response = await nc.request("orders.get", b'{"id": 1001}', timeout=2.0)

Сервис, подписанный на тему, отвечает на тот же канал. Это заменяет прямой вызов по адресу и упрощает обнаружение сервисов.

Сравнение с другими брокерами:

NATS Kafka RabbitMQ
Модель Темы Журнал разделов Очереди и обменники
Хранение Опционально Основной режим До подтверждения
Повторное чтение В JetStream Основной режим Ограниченно
Инфраструктура Один бинарник Кластер и хранилище Отдельный сервер
Пропускная способность Очень высокая Очень высокая Средняя

О выборе между Kafka и RabbitMQ — в статье про выбор брокера.

Сравнение с другими брокерами требует учёта не только возможностей, но и стоимости эксплуатации. NATS запускается одним бинарным файлом без внешних зависимостей, что снижает порог входа. Kafka требует кластера и отдельного хранилища, но даёт длительное хранение журнала и повторное чтение произвольного диапазона. RabbitMQ предоставляет гибкую маршрутизацию через обменники, но хранит сообщения до подтверждения и не рассчитан на повторное чтение истории.

Выбор определяется задачей: уведомления и обнаружение сервисов — NATS, журнал событий с длительным хранением — Kafka, сложная маршрутизация задач — RabbitMQ.

Практика: применение NATS

1. Выбирайте режим по требованию к доставке. Уведомления о состоянии допустимо терять, события, влияющие на данные, требуют JetStream.

2. Проектируйте имена тем иерархически. Структура домен.сущность.событие позволяет подписываться на группу через подстановочный знак.

3. Не используйте подстановочные знаки без необходимости. Подписка на > получает весь трафик, что создаёт нагрузку и раскрывает данные, не нужные сервису.

4. Задавайте таймаут для запроса-ответа. Запрос без таймаута блокирует вызывающий код при недоступности подписчика.

5. Делайте обработчики идемпотентными. При гарантии «не менее одного раза» сообщение может прийти дважды; о порядке — в статье про порядок обработки.

6. Ограничивайте размер сообщения. NATS по умолчанию ограничивает размер, и передача больших данных выполняется по ссылке.

7. Мониторьте отставание подписчиков. В JetStream накопление необработанных сообщений указывает на недостаточную производительность обработчика.

8. Разделяйте потоки по доменам. Один поток на все события усложняет настройку хранения и прав доступа.

Рекомендации:

  1. Начинайте с ядра NATS для уведомлений. Переход на JetStream возможен позже, если потребуется сохранение.
  2. Учитывайте отсутствие схемы сообщения. Формат определяется соглашением, поэтому его изменение требует согласования с подписчиками.
  3. Проверяйте поведение при недоступности подписчика. Различие режимов проявляется именно в этом сценарии.
  4. Используйте группы подписчиков для балансировки. Сообщение обрабатывается одним участником группы, а не всеми.
  5. Фиксируйте срок хранения в JetStream. Без ограничения поток растёт неограниченно.

Практический сценарий: потерянные уведомления при перезапуске сервиса

Контекст: сервис рассылал уведомления через ядро NATS. После обновления подписчика часть уведомлений не дошла, и пользователи не получили сообщения.

  1. Диагностика. Во время перезапуска подписчик отсутствовал несколько секунд. Сообщения, опубликованные в этот период, не были доставлены, поскольку ядро NATS не хранит сообщения для отсутствующих подписчиков.
  2. Причина. Режим выбран без учёта требования к доставке. Уведомления считались некритичными, но пользователи ожидали их получения.
  3. Действия. (а) Поток уведомлений перевели на JetStream с сохранением сообщений; (б) подписчику назначили устойчивое имя, чтобы он продолжил чтение с места остановки; (в) обработчик сделали идемпотентным, поскольку повторная доставка стала возможной; (г) установили срок хранения потока в семь дней; (д) добавили метрику числа необработанных сообщений с тревогой при накоплении.
  4. Результат. Перезапуск подписчика больше не приводит к потере сообщений, а накопление необработанных сообщений обнаруживается метрикой.

Вывод: выбор между ядром NATS и JetStream определяется допустимостью потери сообщения. Для уведомлений, которые пользователь ожидает получить, требуется сохранение, а с ним — идемпотентность обработчика из-за возможной повторной доставки.

FAQ

Чем NATS отличается от Kafka? Моделью: NATS маршрутизирует по темам, Kafka хранит журнал разделов с повторным чтением. JetStream приближает NATS к модели журнала, но Kafka остаётся решением для длительного хранения больших объёмов.

Что происходит, если подписчик отключён? В ядре NATS сообщение теряется. В JetStream оно сохраняется и доставляется после возвращения подписчика.

Поддерживается ли запрос-ответ? Да. Публикация с ожиданием ответа позволяет вызывать сервис без знания его адреса.

Как обрабатывать повторную доставку? Идемпотентностью обработчика: повторная обработка того же сообщения не должна изменять результат.

Источники: NATS docs (Overview, JetStream, Subjects) — ссылки в шапке.