NATS — это простой, быстрый и легковесный брокер сообщений, написанный на языке программирования Go.
У NATS есть несколько особенностей организации данных:
В отличие от многих других брокеров сообщений (например, Apache Kafka или RabbitMQ), NATS имеет несколько весомых преимуществ:
Таким образом, с помощью NATS можно выстраивать быструю и надежную коммуникацию между множеством различных сервисов.
В этом руководстве мы подробно рассмотрим как установить, настроить и корректно использовать NATS в собственных проектах, запущенных на операционной системе Ubuntu 22.04.
cloud
Перед установкой рекомендуется обновить список доступных репозиториев в системе:
sudo apt update
Далее необходимо вручную загрузить ZIP-архив с NATS с его официального репозитория на GitHub:
wget https://github.com/nats-io/nats-server/releases/download/v2.10.22/nats-server-v2.10.22-linux-amd64.zip
По завершении загрузки можно проверить список файлов:
ls
Среди них будет архив с NATS:
nats-server-v2.10.22-linux-amd64.zip resize.log snap
Далее установим пакет, который выполняет распаковку ZIP-архивов:
sudo apt install unzip -y
Флаг -y
добавляем, чтобы установщик автоматически ответил положительно на все возникающие вопросы.
Теперь разархивируем архив с NATS с помощью установленного распаковщика:
unzip nats-server-v2.10.22-linux-amd64.zip
Проверим список файлов:
ls
Как видно, появилась новая папка с содержимым архива:
nats-server-v2.10.22-linux-amd64 nats-server-v2.10.22-linux-amd64.zip resize.log snap
Архив нам больше не нужен, поэтому удаляем его:
rm nats-server-v2.10.22-linux-amd64.zip
Давайте взглянем на содержимое появившейся папки:
ls nats-server-v2.10.22-linux-amd64
Внутри нее есть основная директория с сервером NATS:
LICENSE nats-server README.md
Именно ее мы должны скопировать в системный каталог с бинарными файлами:
sudo mv nats-server-v2.10.22-linux-amd64/nats-server /usr/local/bin/
А уже после копирования необходимо установить соответствующие права доступа:
sudo chmod +x /usr/local/bin/nats-server
Папку с содержимым NATS, по аналогии с архивом, теперь можно тоже удалить:
rm nats-server-v2.10.22-linux-amd64 -R
Сервер NATS можно считать установленным! Давайте убедимся в этом, запросив его версию:
nats-server -v
В консольном терминале появится соответствующий вывод:
nats-server: v2.10.22
Однако эта команда не запускает сервер, а лишь возвращает его версию.
Выполнить запуск сервера можно следующим образом:
nats-server
В консоли должен появиться примерно такой вывод:
[3704] 2024/11/07 02:59:53.908362 [INF] Starting nats-server
[3704] 2024/11/07 02:59:53.908623 [INF] Version: 2.10.22
[3704] 2024/11/07 02:59:53.908669 [INF] Git: [240e9a4]
[3704] 2024/11/07 02:59:53.908701 [INF] Name: NC253DIPURNIY4HUXYQYC5LLAFA6UZEBKUIWTBLLPSMICFH3E2FMSXB7
[3704] 2024/11/07 02:59:53.908725 [INF] ID: NC253DIPURNIY4HUXYQYC5LLAFA6UZEBKUIWTBLLPSMICFH3E2FMSXB7
[3704] 2024/11/07 02:59:53.909430 [INF] Listening for client connections on 0.0.0.0:4222
[3704] 2024/11/07 02:59:53.909679 [INF] Server is ready
В данном случае сервер запускается с привязкой к консольному терминалу, а не как фоновая служба. Поэтому, чтобы обратно выйти в режим ввода команд, нужно нажать сочетание клавиш Ctrl + C
.
После того, как сервер брокера запущен, можно создать отдельный каталог для конфигурационного файла NATS:
mkdir /etc/nats
А после непосредственно сам конфигурационный файл:
sudo nano /etc/nats/nats-server.conf
Его содержимое будет следующим:
cluster {
name: "test-nats"
}
store_dir: "/var/lib/nats"
listen: "0.0.0.0:4222"
Конкретно в этой конфигурации устанавливаются самые базовые параметры:
Для всех каталогов, связанных с NATS, необходимо создать отдельного пользователя:
useradd -r -c 'NATS service' nats
Теперь создадим каталоги, указанные в конфигурационном файле:
mkdir /var/log/nats /var/lib/nats
Для каждой директории назначим соответствующие права доступа для ранее созданного пользователя:
chown nats:nats /var/log/nats /var/lib/nats
Ранее мы запускали сервер NATS с привязкой к консольному терминалу. В этом случае при выходе из консоли сервер будет прекращать свою работу.
Чтобы этого не происходило, необходимо создать файл для службы systemd
:
sudo nano /etc/systemd/system/nats-server.service
Его содержимое будет таким:
[Unit]
Description=Сервер брокера сообщений NATS
After=syslog.target network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/nats-server -c /etc/nats/nats-server.conf
User=nats
Group=nats
LimitNOFILE=65536
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
[Install]
WantedBy=multi-user.target
В этом файле есть несколько ключевых параметров:
Созданную службу необходимо в явном виде добавить в список автозапуска:
systemctl enable nats-server --now
Флаг --now
сразу же запускает указанную службу.
В консоли появится соответствующее сообщение:
Created symlink /etc/systemd/system/multi-user.target.wants/nats-server.service → /etc/systemd/system/nats-server.service.
Теперь проверим статус запущенной службы:
systemctl status nats-server
Если служба сервера NATS запущена успешно, то среди консольного вывода будет соответствующее сообщение:
...
Active: active (running)
...
К серверу NATS можно подключаться через консольный терминал и таким образом выполнять тестирование брокера сообщений. Например, публиковать сообщения или подписывать на темы.
Для того чтобы управлять сервером NATS, необходимо установить соответствующий клиент natscli
, который можно скачать с официального репозитория на GitHub:
wget https://github.com/nats-io/natscli/releases/download/v0.1.5/nats-0.1.5-amd64.deb
После этого загруженный архив можно распаковать и установить:
dpkg -i nats-0.1.5-amd64.deb
А сам архив можно удалить за ненадобностью:
rm nats-0.1.5-amd64.deb
Теперь можно отправить сообщение брокеру сообщений:
nats pub -s 127.0.0.1 "someSubject" "Some message"
В этой команде мы отправляем сообщение «Some message» в тему «someSubject» брокеру сообщений, который запущен по IP-адресу 127.0.0.1
и расположен на стандартном порту NATS — 4222
.
После этого в консольном терминале появится информация об отправленных данных:
19:59:51 Published 12 bytes to "someSubject"
В данный момент никто не увидит это сообщение, так как отсутствует какой-либо агент, подписанный на указанную тему.
Мы можем сымитировать некий сервис, подписанный на тему и читающий сообщения, с помощью другой SSH-сессии.
Для этого нужно открыть еще один консольный терминал, подключиться к удаленной машине и подписаться на ранее указанную тему:
nats sub -s 127.0.0.1 "someSubject"
В терминале появится сообщение об успешной подписке:
20:11:10 Subscribing on someSubject
Теперь повторим отправку сообщения с первого терминала:
nats pub -s 127.0.0.1 "someSubject" "Some message"
Во втором терминале появится информация о новом сообщении:
[#1] Received on "someSubject"
Some message
Отправим еще одно сообщение с первого терминала:
nats pub -s 127.0.0.1 "someSubject" "Some message again"
Во втором терминале появится соответствующее извещение:
[#2] Received on "someSubject"
Some message again
Обратите внимание, что консольный вывод полученных сообщений имеет нумерацию в квадратных скобках.
Давайте создадим небольшую программу на языке программирования Golang с использованием брокера сообщений NATS.
Сперва необходимо убедиться, что в системе установлен компилятор Go:
go version
Если в консольном терминале появилось следующее сообщение, то Go еще не установлен:
Command 'go' not found, but can be installed with:
snap install go # version 1.23.2, or
apt install golang-go # version 2:1.18~0ubuntu2
apt install gccgo-go # version 2:1.18~0ubuntu2
See 'snap info go' for additional versions.
В этом случае его необходимо загрузить в виде архива с официального сайта:
wget https://go.dev/dl/go1.23.3.linux-amd64.tar.gz -O go.tar.gz
А потом извлечь:
sudo tar -xzvf go.tar.gz -C /usr/local
Загруженный архив больше не нужен, поэтому его можно удалить:
rm go.tar.gz
Далее необходимо прописать компилятор Go в переменную PATH
, чтобы его можно было вызывать из терминала консоли:
echo export PATH=$HOME/go/bin:/usr/local/go/bin:$PATH >> ~/.profile
А далее применяем изменения:
source ~/.profile
Теперь можно проверить корректность установки Go, запросив его версию:
go version
В терминале появится следующий вывод:
go version go1.23.3 linux/amd64
Создадим отдельную папку для программы на Golang:
mkdir nats_go
После чего перейдем в нее:
cd nats_go
А далее инициализируем проект Go:
go mod init nats_go
После инициализации проекта необходимо установить клиент NATS с официального репозитория на GitHub. Вручную ничего загружать не надо, достаточно воспользоваться встроенной в Golang функцией:
go get github.com/nats-io/nats.go/
Теперь можно создать файл с кодом программы:
nano nats_go.go
Его содержимое будет таким:
package main
import (
"fmt" // модуль для работы с консолью
"os" // модуль для работы с системными функциями
"time" // модуль для работы с временем
"github.com/nats-io/nats.go" // модуль для работы с сервером NATS
)
func main() {
// получаем адрес сервера NATS из переменной среды
url := os.Getenv("NATS_URL")
// если в переменной среды нет адреса, используем адрес по умолчанию
if url == "" {
url = nats.DefaultURL
}
// выполняем подключение к серверу NATS
nc, _ := nats.Connect(url)
// откладываем очистку брокера сообщений до момента завершения функции main()
defer nc.Drain()
// отправляем сообщение в тему без подписчиков, чтобы убедиться, что оно пропадет
nc.Publish("people.philosophers", []byte("Привет, Сократ!"))
// подписываемся на все подтемы в теме «people»
sub, _ := nc.SubscribeSync("people.*")
// извлекаем сообщение
msg, _ := sub.NextMsg(10 * time.Millisecond)
// выводим статус сообщения (его нет, т.к. оно было отправлено до подписки на темы)
fmt.Printf("Сообщения нет? Ответ: %v\n", msg == nil)
// отправляем сообщение в подтему «philosophers» темы «people»
nc.Publish("people.philosophers", []byte("Привет, Сократ!"))
// отправляем сообщение в подтему «physicists» темы «people»
nc.Publish("people.physicists", []byte("Привет, Фейнман!"))
// извлекаем сообщение и выводим в консоль
msg, _ = sub.NextMsg(10 * time.Millisecond)
fmt.Printf("Сообщение: %q в теме %q\n", string(msg.Data), msg.Subject)
// извлекаем сообщение и выводим в консоль
msg, _ = sub.NextMsg(10 * time.Millisecond)
fmt.Printf("Сообщение: %q в теме %q\n", string(msg.Data), msg.Subject)
// отправляем сообщение в подтему «biologists» темы «people»
nc.Publish("people.biologists", []byte("Привет, Дарвин!"))
// извлекаем сообщение и выводим в консоль
msg, _ = sub.NextMsg(10 * time.Millisecond)
fmt.Printf("Сообщение: %q в теме %q\n", string(msg.Data), msg.Subject)
}
Теперь можно запустить созданную программу:
go run .
Результат работы программы появится в выводе консольного терминала:
Сообщения нет? Ответ: true
Сообщение: "Привет, Сократ!" в теме "people.philosophers"
Сообщение: "Привет, Фейнман!" в теме "people.physicists"
Сообщение: "Привет, Дарвин!" в теме "people.biologists"
В качестве еще одного примера рассмотрим использование брокера сообщений NATS в языке программирования Python.
Сперва нужно убедиться, что интерпретатор Python установлен в системе, запросив его версию:
python --version
В консоли появится соответствующее сообщение:
Python 3.10.12
Обратите внимание, что в этом руководстве используется Python версии 3.10.12
.
Для загрузки клиента NATS для Python сперва необходимо установить пакетный менеджер PIP:
apt install python3-pip -y
Флаг -y
поможет автоматически положительно ответить на все вопросы во время установки.
Теперь можно установить клиент NATS для Python:
pip install nats-py
Для программы на Python создадим отдельный каталог:
mkdir nats_python
И перейдем в него:
cd nats_python
Создадим файл с кодом программы:
nano nats_python.py
Содержимое которого будет следующим:
import os
import asyncio
# импортируем клиент NATS
import nats
from nats.errors import TimeoutError
# получение переменной окружения, в которой хранится адрес сервера NATS
servers = os.environ.get("NATS_URL", "nats://localhost:4222").split(",")
async def main():
# подключение к серверу NATS
nc = await nats.connect(servers=servers)
# отправляем сообщение в тему без подписчиков, чтобы убедиться, что оно пропадет
await nc.publish("people.philosophers", "Привет, Сократ!".encode())
# подписываемся на все подтемы в теме «people»
sub = await nc.subscribe("people.*")
try:
# извлекаем сообщение
msg = await sub.next_msg(timeout=0.1)
except TimeoutError:
pass
# отправляем сообщение в подтему «philosophers» темы «people»
await nc.publish("people.philosophers", "Привет, Сократ!".encode())
# отправляем сообщение в подтему «physicists» темы «people»
await nc.publish("people.physicists", "Привет, Фейнман!".encode())
# извлекаем сообщение и выводим в консоль
msg = await sub.next_msg(timeout=0.1)
print(f"{msg.data.decode('utf-8')} в теме {msg.subject}")
# извлекаем сообщение и выводим в консоль
msg = await sub.next_msg(timeout=0.1)
print(f"{msg.data.decode('utf-8')} в теме {msg.subject}")
# отправляем сообщение в подтему «biologists» темы «people»
await nc.publish("people.biologists", "Привет, Дарвин!".encode())
# извлекаем сообщение и выводим в консоль
msg = await sub.next_msg(timeout=0.1)
print(f"{msg.data.decode('utf-8')} в теме {msg.subject}")
# отписываемся от тем
await sub.unsubscribe()
# очищаем брокер сообщений
await nc.drain()
if __name__ == '__main__':
asyncio.run(main())
Теперь можно запустить созданный скрипт:
python nats_python.py
Результатом его работы станет следующий вывод в консольном терминале:
Привет, Сократ! в теме people.philosophers
Привет, Фейнман! в теме people.physicists
Привет, Дарвин! в теме people.biologists
Как можно заметить, логика работы этой программы на Python ничем не отличается от логики работы программы на Go. Разница лишь в синтаксических конструкциях конкретного языка программирования.
Подготовили для вас выгодные тарифы на VDS
В этом руководстве было рассмотрено использование брокера сообщений NATS в виде последовательных этапов:
Все используемые в этом руководстве клиенты NATS (для терминала, Go и Python) были загружены с официального репозитория NATS на GitHub, в котором размещаются модули и библиотеки для всех поддерживаемых NATS языков программирования.
Больше подробной информации о настройке и использовании NATS можно найти в официальной документации. Также есть множество официальных примеров использования NATS в разных языках программирования.