MQTT
Лёгкий протокол обмена сообщениями по модели публикация-подписка поверх TCP, ставший стандартом де-факто для телеметрии IoT-устройств.
Что такое MQTT
MQTT — лёгкий протокол обмена сообщениями поверх TCP, построенный на модели publish/subscribe. Устройство не отправляет данные другому устройству напрямую: оно публикует сообщение в тему (topic) на брокере, а брокер рассылает его всем, кто на эту тему подписан. Отправитель не знает, кто и сколько получателей его читает, — и наоборот.
Расшифровка: исторически MQTT — MQ Telemetry Transport, где MQ пришло от продукта IBM MQ Series (часто встречается и вариант Message Queuing Telemetry Transport). Протокол создали в 1999 году Энди Стэнфорд-Кларк (IBM) и Арлен Ниппер для сбора телеметрии нефтепровода через спутниковый канал: отсюда требования — минимум служебного трафика и живучесть на нестабильной связи. В стандарте OASIS название закреплено просто как MQTT и аббревиатурой уже не считается.
Минимальный заголовок пакета — 2 байта. Именно поэтому MQTT вытеснил HTTP в IoT: на датчике, который шлёт число раз в минуту, заголовки HTTP-запроса весят больше самих данных.
Как устроен обмен
ESP32 (publisher) Брокер Дашборд (subscriber)
| | |
|--- CONNECT --------------------->|<--- CONNECT -----------------|
|<-- CONNACK ----------------------|---- CONNACK --------------->|
| |<--- SUBSCRIBE home/+/temp ---|
| |---- SUBACK ---------------->|
|--- PUBLISH home/kitchen/temp --->| |
| payload: 21.5 |---- PUBLISH --------------->|
Брокер — единственный обязательный сервер в схеме: он держит постоянные TCP-соединения со всеми клиентами и маршрутизирует сообщения по темам.
Темы (topics)
Тема — строка с уровнями через /, от общего к частному. Заранее создавать её не нужно: тема существует ровно в момент публикации.
factory/line-3/press-01/temperature
factory/line-3/press-01/state
home/kitchen/sensor-1/temperature
- Регистр важен:
Home/tempиhome/temp— разные темы. - Ведущего
/лучше избегать:/home/tempсоздаёт пустой первый уровень. - Темы вида
$SYS/...зарезервированы под статистику самого брокера.
Подстановки работают только в подписке, публиковать в шаблон нельзя:
| Шаблон | Значение | Пример |
|---|---|---|
+ |
ровно один уровень | home/+/temperature совпадёт с home/kitchen/temperature, но не с home/1/2/temperature |
# |
все оставшиеся уровни, только в конце темы | factory/# — всё поддерево цеха |
QoS — уровни гарантии доставки
| QoS | Гарантия | Обмен пакетами | Риск |
|---|---|---|---|
| 0 | at most once — отправил и забыл | PUBLISH | сообщение может потеряться |
| 1 | at least once | PUBLISH → PUBACK | возможны дубликаты |
| 2 | exactly once | PUBLISH → PUBREC → PUBREL → PUBCOMP | нет, но самый дорогой |
Три момента, которые чаще всего понимают неверно:
- QoS действует на одном участке, а не сквозь всю систему. Публикация издатель → брокер и доставка брокер → подписчик согласуются отдельно. Подписчик получит сообщение с QoS = min(QoS публикации, QoS подписки): опубликовав с QoS 2, но подписавшись с QoS 0, гарантий вы не получите.
- QoS 1 требует идемпотентности. При потере PUBACK клиент повторит PUBLISH с флагом DUP, и обработчик увидит значение дважды. Для счётчика «прибавить 1» это ошибка, для «температура = 21.5» — нет.
- QoS 2 стоит четырёх пакетов и задержки. Он нужен там, где дубль недопустим: команда управления, биллинговое событие.
На практике: частая телеметрия — QoS 0 (следующее значение придёт через секунду и всё равно перекроет потерянное), обычные измерения и события — QoS 1, команды и деньги — QoS 2.
Retained, LWT и keepalive
- Retained-сообщение: брокер хранит последнее сообщение темы и отдаёт его новому подписчику сразу при подписке. Без этого дашборд после перезагрузки показывал бы пустые поля до следующего измерения. Retained-сообщение в теме одно — новое затирает старое.
- LWT (Last Will and Testament): клиент при подключении регистрирует «завещание» — сообщение, которое брокер опубликует сам, если соединение оборвётся некорректно. Классика:
home/kitchen/sensor-1/statusсо значениемoffline. - Keepalive: интервал, заявленный в CONNECT. Если клиент молчит дольше полутора интервалов, брокер считает его отключившимся и публикует LWT. Для поддержания тишины клиент шлёт PINGREQ.
- Постоянная сессия: при
clean session = false(в MQTT 5 — session expiry) брокер копит сообщения QoS 1–2 для отключившегося клиента и отдаёт их при возврате.
Практика: Mosquitto
# Брокер Eclipse Mosquitto в Docker со своим конфигом
docker run -d --name mosquitto -p 1883:1883 -p 8883:8883 \
-v /srv/mosquitto/config:/mosquitto/config \
-v /srv/mosquitto/data:/mosquitto/data \
eclipse-mosquitto
# Подписаться на температуру всех комнат (-v печатает тему рядом со значением)
mosquitto_sub -h 192.168.1.10 -t 'home/+/temperature' -v
# Опубликовать значение с QoS 1 и флагом retain
mosquitto_pub -h 192.168.1.10 -t 'home/kitchen/temperature' -m '21.5' -q 1 -r
# Подписка на всё поддерево цеха через TLS
mosquitto_sub -h mqtt.example.com -p 8883 --cafile ca.crt \
-u sensor01 -P secret -t 'factory/#' -v
Частая ошибка при первом запуске: начиная с версии 2.0 Mosquitto по умолчанию слушает только localhost и запрещает анонимные подключения. Для доступа извне нужен свой mosquitto.conf с явным listener 1883 и настроенной аутентификацией — «не подключается снаружи» почти всегда именно это, а не сеть.
MQTT 3.1.1 и MQTT 5
MQTT 5 обратно совместим по идеям, но заметно богаче:
- Reason codes — брокер объясняет отказ, а не просто рвёт соединение (в 3.1.1 отладка прав доступа была гаданием).
- Shared subscriptions (
$share/группа/тема) — несколько подписчиков делят поток сообщений, то есть балансировка нагрузки средствами протокола. - Topic alias — длинная тема заменяется коротким числовым псевдонимом, экономия на каждом пакете.
- Message expiry и session expiry — устаревшие сообщения не доставляются «из прошлого».
- User properties — произвольные заголовки рядом с payload.
Брокеры и инфраструктура
| Брокер | Особенность |
|---|---|
| Eclipse Mosquitto | лёгкий, один процесс на C; тянет одноплатник или роутер с OpenWrt |
| EMQX | кластеризация и маршрутизация правилами, для крупных парков устройств |
| HiveMQ | enterprise-вариант с кластером и расширениями |
| RabbitMQ | MQTT через плагин — разумно, если AMQP уже используется |
Порты: 1883 — открытый MQTT, 8883 — MQTT поверх TLS; оба закреплены за протоколом официально. Для браузерных дашбордов брокеры дополнительно отдают MQTT поверх WebSocket — порт зависит от брокера и задаётся в конфиге.
Брокер обычно живёт на VPS рядом с остальной платформой: он держит тысячи долгих TCP-соединений, поэтому важнее лимиты файловых дескрипторов и стабильность сети, чем процессор. Дальше поток часто уходит в Kafka и БД временных рядов вроде InfluxDB.
Связанные термины
Готовы запустить GPU-задачу?
Запустить GPU-сервер