MAATRIX / Блог / NATS на Ubuntu 24.04: пошаговая установка

NATS на Ubuntu 24.04: пошаговая установка

MAATRIX

Если микросервисы общаются через HTTP-запросы напрямую друг к другу, рано или поздно это превращается в клубок таймаутов и каскадных падений. NATS решает эту проблему проще, чем Kafka или RabbitMQ: один бинарник, минимум конфигурации, задержки в единицы миллисекунд и топология pub/sub, которая ложится в голову за десять минут. Ниже — установка с нуля на чистой Ubuntu 24.04, от systemd-юнита до JetStream и TLS.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Почему NATS, а не Kafka или RabbitMQ

NATS выигрывает там, где не нужна сложная маршрутизация с десятками exchange-типов (как в RabbitMQ) и не нужен распределённый лог с ребалансировкой партиций (как в Kafka). Это брокер для сценариев «сервис A публикует событие — сервисы B и C его получают», request-reply между микросервисами и лёгкого service discovery.

Ключевые отличия на практике:

  • Ресурсы. Сервер NATS — это один статический бинарник на Go без внешних зависимостей (даже без JVM, как у Kafka). На 1-2 ГБ RAM он спокойно держит десятки тысяч сообщений в секунду.
  • Простота эксплуатации. Конфиг — один файл, без ZooKeeper и без отдельного кластера метаданных.
  • At-most-once по умолчанию. Базовый NATS не гарантирует доставку — сообщение теряется, если подписчика нет онлайн. Для надёжной доставки с persistence нужен JetStream (встроенное расширение, включается одной опцией).
  • Не для тяжёлого стриминга. Если нужен long-term retention на терабайты с consumer groups и replay истории на глубину месяцев — это ближе к Kafka.

Если ваш случай — событийная шина между микросервисами, кэш-инвалидация, IoT-телеметрия или request-reply вместо синхронных HTTP-вызовов — NATS почти всегда быстрее развернуть и дешевле держать в проде.

Требования к серверу и подготовка

Для теста хватит 1 vCPU / 1 ГБ RAM, для продакшена с JetStream и десятками тысяч сообщений в секунду разумный старт — 2 vCPU / 4 ГБ RAM, а диск важен, если включаете персистентность (JetStream пишет данные на диск, и под нагрузкой лучше NVMe SSD, а не сетевой HDD).

Обновите систему и создайте отдельного пользователя — не запускайте брокер под root:

sudo apt update && sudo apt upgrade -y
sudo useradd --system --no-create-home --shell /usr/sbin/nologin nats

Проверьте архитектуру — она понадобится для скачивания правильного бинарника:

uname -m
# x86_64 → amd64
# aarch64 → arm64

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Установка бинарника NATS Server

Официальный способ — скачать релиз с GitHub. На момент написания статьи актуальная стабильная ветка — 2.10.x; проверьте страницу релизов nats-io/nats-server на случай более свежей версии — версии обновляются часто, и вшивать конкретный номер в статью смысла нет.

NATS_VERSION="v2.10.22"
ARCH="amd64"   # или arm64, если сервер на ARM

curl -L -o /tmp/nats-server.tar.gz \
  "https://github.com/nats-io/nats-server/releases/download/${NATS_VERSION}/nats-server-${NATS_VERSION}-linux-${ARCH}.tar.gz"

tar -xzf /tmp/nats-server.tar.gz -C /tmp
sudo install -m 755 /tmp/nats-server-${NATS_VERSION}-linux-${ARCH}/nats-server /usr/local/bin/nats-server

Проверьте, что бинарник рабочий:

nats-server --version

Заодно поставьте CLI-клиент nats — им удобно публиковать/читать сообщения при отладке, без него придётся писать тестовый код на Go или Python:

curl -sf https://binaries.nats.dev/nats-io/natscli/nats@latest | sh
sudo mv nats /usr/local/bin/nats

Базовая конфигурация

Создайте директории для конфига и данных JetStream:

sudo mkdir -p /etc/nats /var/lib/nats/jetstream
sudo chown -R nats:nats /var/lib/nats

Минимальный конфиг /etc/nats/nats-server.conf:

# Сетевой интерфейс и порт клиентских подключений
listen: 0.0.0.0:4222

# Мониторинг (HTTP, порт /varz, /connz и т.д.)
http_port: 8222

# JetStream — персистентность и at-least-once доставка
jetstream {
  store_dir: "/var/lib/nats/jetstream"
  max_mem: 1G
  max_file: 10G
}

# Логирование
log_file: "/var/log/nats/nats-server.log"
logtime: true

# Лимиты соединений — разумный старт для прод-сервера
max_connections: 10000
max_payload: 1MB

Создайте директорию логов и выставьте права:

sudo mkdir -p /var/log/nats
sudo chown nats:nats /var/log/nats /etc/nats/nats-server.conf

Аутентификация и авторизация

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

authorization {
  users = [
    { user: "app-order-service", password: "$2a$11$замените-на-bcrypt-хэш", permissions: {
        publish: ["orders.>"]
        subscribe: ["orders.>", "_INBOX.>"]
      }
    }
    { user: "app-notify-service", password: "$2a$11$другой-bcrypt-хэш", permissions: {
        publish: ["notifications.>"]
        subscribe: ["orders.created", "_INBOX.>"]
      }
    }
  ]
}

Пароли лучше не хранить в открытом виде — сгенерируйте bcrypt-хэш штатной утилитой:

nats server passwd
# введите пароль интерактивно, получите готовый хэш для конфига

Обратите внимание на permissions — это тонкая настройка того, в какие subject'ы (топики) сервис может публиковать и на что подписываться. orders.> означает «всё, что начинается с orders.» — удобно разграничивать сервисы по неймспейсам, чтобы order-service физически не мог опубликовать событие в топик notifications. Для более серьёзных сценариев (динамическое управление ключами, множество тенантов) в NATS есть NKeys и decentralized JWT auth, но для старта bcrypt-пользователей в конфиге достаточно.

Systemd-юнит и запуск

Создайте /etc/systemd/system/nats-server.service:

[Unit]
Description=NATS Server
After=network.target

[Service]
Type=simple
User=nats
Group=nats
ExecStart=/usr/local/bin/nats-server -c /etc/nats/nats-server.conf
ExecReload=/bin/kill -SIGHUP $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

# Небольшое ужесточение — сервис не лезет куда не надо
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/var/lib/nats /var/log/nats
ProtectHome=true

[Install]
WantedBy=multi-user.target

LimitNOFILE=65536 важен: у NATS каждое клиентское соединение — это файловый дескриптор, и дефолтный лимит в 1024 упрётся в потолок гораздо раньше, чем закончится CPU.

Запустите и включите в автозагрузку:

sudo systemctl daemon-reload
sudo systemctl enable --now nats-server
sudo systemctl status nats-server

Проверьте, что сервер слушает нужные порты:

ss -tlnp | grep nats-server

Файрвол и проверка работы

Порт 4222 нужно открыть только тем сервисам, которым он реально нужен — в идеале NATS сидит в приватной сети/VPC, а наружу торчит только через VPN или в пределах одного дата-центра. Если открываете порт публично через ufw, ограничьте источник:

sudo ufw allow from 10.0.0.0/16 to any port 4222 proto tcp
sudo ufw allow from 10.0.0.0/16 to any port 8222 proto tcp comment "nats monitoring"

Если ufw ещё не настроен на сервере в принципе, у нас есть отдельный разбор — firewall ufw на Ubuntu 24.04 с базовыми правилами и типичными граблями.

Проверка через CLI-клиент — подпишитесь на тестовый subject в одном терминале:

nats sub "test.hello"

И опубликуйте сообщение из другого:

nats pub "test.hello" "привет из nats"

Если первое окно показало сообщение — брокер работает. Мониторинговый эндпоинт http://<IP>:8222/varz отдаёт JSON со статистикой (число соединений, объём трафика, аптайм) — его удобно скармливать в Prometheus через nats-exporter. Если уже поднимали стек мониторинга, см. статью про Grafana и Prometheus на Ubuntu 24.04 — добавить nats-exporter как ещё один таргет не сложнее, чем дописать job в prometheus.yml.

JetStream: потоки и надёжная доставка

Базовый NATS — это pub/sub без сохранения истории: если подписчика нет онлайн в момент публикации, сообщение теряется безвозвратно. JetStream добавляет поверх этого персистентные потоки (streams) и consumer'ов с подтверждением доставки (acknowledgement) — то есть настоящий at-least-once.

Создайте поток для заказов:

nats stream add ORDERS \
  --subjects "orders.>" \
  --storage file \
  --retention limits \
  --max-msgs=-1 \
  --max-bytes=-1 \
  --max-age=720h \
  --replicas=1

--max-age=720h — хранить сообщения 30 дней, дальше они вытесняются автоматически. Для стенда с одним нодом --replicas=1 — это ожидаемо; для отказоустойчивости на проде JetStream умеет реплицировать поток на 3 ноды кластера (Raft-консенсус), но это уже отдельная тема кластеризации.

Создайте durable consumer — подписчика, который помнит свою позицию даже после перезапуска:

nats consumer add ORDERS order-processor \
  --filter "orders.created" \
  --ack explicit \
  --pull \
  --max-deliver=5

--ack explicit требует явного подтверждения обработки каждого сообщения — если сервис упал до ack, сообщение переотправится (до 5 попыток из --max-deliver). Это и есть механизм надёжной доставки, которого не хватает в голом NATS.

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

nats stream info ORDERS
nats stream view ORDERS

Для сравнения: если задача — не событийная шина, а классическая очередь задач с гарантированной доставкой и сложной маршрутизацией по exchange/routing key, присмотритесь к RabbitMQ; NATS JetStream закрывает похожий кейс, но с более простой моделью subject-based routing.

TLS-шифрование трафика между сервисами

Если клиенты подключаются не по приватной сети, а через интернет (например, сервисы разнесены между дата-центрами), трафик стоит шифровать. Проще всего — получить сертификат Let's Encrypt на домен, указывающий на сервер, и подключить его в конфиг:

tls {
  cert_file: "/etc/letsencrypt/live/nats.example.com/fullchain.pem"
  key_file:  "/etc/letsencrypt/live/nats.example.com/privkey.pem"
  timeout: 5
  verify: true
}

verify: true включает mTLS — сервер потребует клиентский сертификат при подключении, что полезно, когда у вас закрытая экосистема микросервисов и вы хотите исключить подключение случайных клиентов даже с правильным паролем. Для выпуска и обновления сертификата удобно использовать Caddy или certbot — если ещё не настраивали автоматический TLS на сервере, у нас есть разбор Caddy с авто-SSL на Ubuntu 24.04, логика получения сертификата там та же, меняется только то, куда класть файлы.

После правки конфига перечитайте его без остановки сервиса:

sudo systemctl reload nats-server

Проверьте подключение с TLS:

nats sub "test.hello" --tlsca /etc/letsencrypt/live/nats.example.com/fullchain.pem \
  -s tls://nats.example.com:4222

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Чем NATS принципиально отличается от Redis Pub/Sub?

Redis Pub/Sub — это побочная функция ин-мемори базы, без персистентности и без гарантий доставки вообще. NATS — специализированный брокер: даже в базовом режиме он лучше держит большое число подписчиков и subject-based маршрутизацию с wildcard'ами (orders.*, orders.>), а с JetStream добавляет надёжную доставку. Если вы уже держите Redis на сервере ради кэша, для несложной шины событий его Pub/Sub тоже подойдёт — но не рассчитывайте на него как на надёжную очередь. Ставили Redis раньше — вот наш разбор установки Redis на VPS.

Нужен ли кластер из нескольких нод для продакшена?

Не обязательно. Один инстанс NATS с JetStream на SSD прекрасно работает в проде для среднего трафика — риски те же, что у любого single-node сервиса: если сервер упал, брокер недоступен, пока не поднимется заново. Кластер из 3+ нод с Raft-репликацией потоков нужен, когда простой брокера недопустим бизнесом или трафик уже не помещается в один сервер.

Как посмотреть, кто подключён к серверу прямо сейчас?

curl http://localhost:8222/connz — отдаст JSON со списком активных соединений, их IP, subject'ами подписок и объёмом трафика. Удобно при отладке, кто именно заспамил брокер.

Что будет с сообщениями в JetStream, если кончится место на диске?

Поток остановит приём новых сообщений с ошибкой insufficient storage, старые данные при этом не тронутся — если только не настроен --max-bytes с автоматическим вытеснением по лимиту. Мониторьте /varz или подключайте алерты на заполнение /var/lib/nats, чтобы не поймать это в проде.

Можно ли использовать NATS вместо Kafka для стриминга событий с длинной историей?

Технически JetStream умеет хранить историю сколь угодно долго (--max-age, --max-bytes без ограничений), но экосистема вокруг Kafka — коннекторы, консьюмеры на разных языках, инструменты для аналитики поверх лога событий — заметно богаче. Для чистого event streaming с построением аналитики поверх истории Kafka по-прежнему более зрелый выбор; NATS выигрывает простотой эксплуатации и низкой задержкой.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →