`

СПЕЦІАЛЬНІ
ПАРТНЕРИ
ПРОЕКТУ

Чи використовує ваша компанія ChatGPT в роботі?

BEST CIO

Определение наиболее профессиональных ИТ-управленцев, лидеров и экспертов в своих отраслях

Человек года

Кто внес наибольший вклад в развитие украинского ИТ-рынка.

Продукт года

Награды «Продукт года» еженедельника «Компьютерное обозрение» за наиболее выдающиеся ИТ-товары

 

Андрей Зубинский

Протокол MQTT (и немного из опыта реализации). Часть 1.

+77
голосов

Несмотря на растущую популярность и де-юре стандартность MQTT в мире «большой автоматики» (этот факт подтверждается принятием MQTT в качестве стандарта концерном OASIS, объединяющим более пяти тысяч участников из 65 стран и являющимся системообразующим в мире IT), вменяемой информации ни на украинском, ни на русском языках, я о нём не находил, потому решил собрать свой опыт «разбора по косточкам» текста стандарта.

Несмотря на компактность, собственно текст стандарта написан очень «распылённо», многие очевидные (после тщательного изучения) вещи в нём «спрятаны» методом «разбрасывания» по тексту. В общем, попробую восстановить возможную понятийную иерархию и логику из этого документа, а также дополню стандарт теми сведениями, которые по моему мнению важны.

Два слова об истории протокола. Он был создан ещё в 1999 году, в исследовательском центре IBM, всего двумя разработчиками (Энди Стэнфорд-Кларком, IBM, и Эрлоном Ниппером, Cirrus Link Solution). Это важный факт, и вовсе не для «необязательной иллюстративной истории». Протоколы, созданные малыми рабочими группами или даже отдельными личностями, отличаются компактностью и «обозримостью». А уже эти два фактора во многом определяют скорость появления, живучесть и распространение разработок на основе таких протоколов.

Довольно долго MQTT был внутренним протоколом IBM, затем он был открыт (подразумевается полная открытость, без каких-либо патентных и прочих ограничений) и использован, например, Facebook (в мессенджере). Динамику изменения интереса к MQTT можно косвенно оценить с помощью Google Trends, разумно также сравнить интерес к MQTT с интересом к специально созданному практически для IoT протоколу COAP. Картина будет выглядеть так (синий – MQTT, красный – COAP):

Протокол MQTT (и немного из опыта реализации). Часть 1.

Фактически экспоненциальный рост интереса – следствие целого ряда причин, которым и будет посвящено всё остальное.

Начнём с главного. Согласно стандарту, MQTT – сугубо транспортный протокол (что немного не так, более точно было бы говорить об управляемом свободно задаваемой семантикой механизме транспортировки, но об этом позже), поэтому всё, что связано с безопасностью и защитой механизмов транспорта, выходит за его пределы.

Кроме того, стандарт MQTT требует от используемого низкоуровневого (по отношению к MQTT) сетевого соединения способности «без потерь доставлять потоки байтов с сохранением упорядоченности в любых направлениях» (так что, например, можно сразу забыть о легковесном UDP и прочем).

Двух предыдущих абзацев более достаточно, чтобы понять – для «сверхтонких» вычислителей (масштабов «умной пыли», smart dust) MQTT, по логике, не совсем подходит – слишком многого он требует от всего необходимого стека протоколов, и за этим многим стоит, конечно же:

  • повышение требований к производительности, объёмам памяти (программ и оперативной);
  • увеличенное энергопотребление;
  • и, наконец, самое неприятное, что может быть в действительно масштабных инсталляциях программно-аппаратных систем – к необходимости сопровождения больших программных стеков, требующей постоянных исправлений и обновлений объёмного ПО, управления огромными сетями и необходимыми ресурсами (например, ключами подсистем шифрования).

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

Умышленно вынесенная в самое начало важная специфическая особенность MQTT заставляет хорошо задуматься об оптимальном применении протокола и архитектуре систем на его основе, но пока для этого рано. Главное, – не забывать основной инженерный принцип «не существует оптимальных для любых условий систем», и не пытаться адаптировать что-то для применений, где оно явно не на своём месте (анализ областей применимости – отдельная недешёвая операция в любом проектном процессе, но экономия на нём оборачивается поздними серьёзными убытками). Можно, конечно, забавляться «MQTT на Arduino», но для «настоящих применений» такой подход будет слишком далёк от требований и возможностей реальности.

Ключевые элементы коммуникационной системы, описываемой протоколом MQTT – клиент (client) и сервер (server, в ранних редакциях стандарта MQTT – broker).

Каждый клиент MQTT обязан иметь уникальный идентификатор ClientId, представленный UTF-8 строкой с числом символов от 1 до 23. В строке ClientId допускается использование только символов [a-z, A-Z, 0-9].

Максимальное количество уникальных идентификаторов для MQTT клиентов оценивается числом 6223 или примерно 1,6*1041. Идентификаторы клиентов используются исключительно сервером и только для организации единой сессии работы клиента и сервера при множественных подключениях и отключениях клиента с сервером на уровне сетевого соединения. Несмотря на обязательность наличия ClientId, стандарт допускает вариант работы клиента и сервера, при которой клиент указывает "пустой" ClientId (это специальный случай работы «с чистого листа», о нём дальше).

Представление ClientId даёт первый пример важной детали протокола – в пакетах MQTT практически везде используются UTF-8 строки с определённым стандартом Unicode множеством недопустимых символов (соответствующие требованию «well-formed UTF-8») и префиксным явным бинарным двухбайтовым указанием длины, так что когда в дальнейшем будет употребляться термин «MQTT UTF-8 строка», он будет обозначать такую конструкцию:

Протокол MQTT (и немного из опыта реализации). Часть 1.

Стандарт декларирует принадлежность протокола к классу архитектурных паттернов Pub/Sub и частичную симметричность (Pub-симметричность) протокола. Это требует детального пояснения.

Архитектурный паттерн Pub/Sub определяет класс «сильно слабосвязанных» систем, в которых участники обмена информацией вообще не обязаны знать о существовании друг друга. Кроме того, в этих системах может вообще не использоваться традиционная сетевая «адресация узлов» (или использоваться, но не на уровне фундаментального принципа, а сугубо в служебных целях, как ClientId в MQTT). Всё строится на данных и их метаинформации. «Издатель» (Pub, Publisher) «публикует» данные и метаинформацию (формирует описанные метаинформацией «каналы»), «подписчик» (Sub, Subscriber) «подписывается» на «каналы», определённые метаинформацией. Если для подписки на метаинформацию данные от «издателя» есть, «подписчик» их получает. Если таких данных нет – ничего не происходит вообще, никто не запрещает «подписываться» на несуществующие «каналы», никаких ограничений нет.

В терминах MQTT транспортируемые данные и метаинформация, формирующая «каналы» транспорта, представлены MQTT UTF-8 строками. Строки метаинформации формируются из фрагментов, имеющих название топиков (topic), предусмотрены специальные символы и правила форматирования, вводящие иерархию топиков и возможность «подписки» на множества каналов за счёт wildcards. Эти «специальные правила» и wildcards хорошо знакомы всем, кто хоть раз пользовался любой командной оболочкой при работе с файловой системой.

Иерархия формируется соединением топиков с помощью символа «/», например строка:

room1/north_wall/temperature

состоит из трёх топиков (room1, north_wall, temperature), очевидно формирующих некоторые иерархические отношения (в комнате №1 находится северная стена и на ней измеряется температура). Почти никаких ограничений кроме well-formed UTF-8 на текст топиков не существует, это область полной свободы для разработчиков конкретных приложений.

При этом (всё до конца абзаца выходит далеко за рамки стандарта MQTT) уже существуют несколько общепринятых подходов к формированию систем топиков. Вообще, это исключительно важный момент в MQTT, обычно недооцениваемый. Потому что топики вводят семантику, на основе которой работает механизм транспорта данных MQTT. Распространены, условно говоря, физический и «машинный» подходы (никакой устоявшейся терминологии здесь нет). Физический – описание топиками иерархической структуры объектов мира и связанных с ними абстракций, «машинный» - описание организации машинной системы в традиционных, например, для компьютерных сетей, терминах. Физический подход уже проиллюстрирован примеров выше, его «машинный» аналог может выглядеть так:

идентификатор_сети/GUID_контроллера_в_сети
/ID_измерительного_канала_контроллера

Семантическое управление транспортом данных в MQTT – очень важная область, которую стандарт MQTT совершенно не затрагивает (иначе он стал бы необозримым). И очень интересная область, в которой «распространённое» совершенно не означает «хорошее». Но это вообще тема для отдельного обсуждения.

Теперь о wildcards. Они позволяют задавать одним символом множество каналов сразу. Понятно, что именно поэтому при «публикации» данных в метаинформации они недопустимы (метаинформация о публикуемых данных должна быть точно определена, чтобы до данных можно было «добраться»), и стандарт MQTT это понятное формулирует строго – wildcards в Pub-метаинформации (строке, состоящей из топиков и символов иерархии) категорически не должно быть. Текущая версия стандарта не определяет поведение MQTT сервера при получении pub-метаинформации, содержащей wildcards, но, если следовать довольно строгой логике разработчиков протокола (её легко заметить при изучении стандарта), обнаружив такое (как и любое нарушение правила «всё должно быть well-formed UTF-8 string»), сервер должен разрывать сетевое соединение с клиентом-нарушителем правил (хотя бы потому, что возможность инжекции любой неправильной метаинформации в единый механизм управляемого семантикой транспорта данных может использоваться для атак на систему).

В метаинформации о подписке возможны всего два символа wildcards – «#» и «+». Первый обозначает «всю под-иерархию топиков», второй «весь только один уровень иерархии». Это лучше всего пояснить на простом примере. Пусть в MQTT-системе опубликованы следующие пять иерархий топиков:
L0
L0/L1
L0/L1/L2
L0/L1/L2/L3.1
L0/L1/L2/L3.2
L0/L1/L2/L3/L4

Использование «#», например, L0/L1/L2/# , формирует сразу четыре канала транспорта данных:

L0/L1/L2
L0/L1/L2/L3.1
L0/L1/L2/L3.2
L0/L1/L2/L3/L4

В свою очередь, L0/L1/L2/+ задаёт только три канала:

L0/L1/L2/L3.1
L0/L1/L2/L3.2

L0/L1/L2/L3

Описание подписки на множественные каналы может содержать любые правильно описанные комбинации wildcards, использование повторяющихся неразделённых «/» символов wildcards стандартом запрещено.

Не совсем специальный топик, состоящий из одного wildcard символа «#» не просто разрешён стандартом и логично описывается фразой «подписываюсь на всё», он используется в том числе для связи серверов MQTT между собой, то есть, для формирования единого пространства топиков в многосерверной системе, что обеспечивает единый механизм управляемого семантикой топиков транспорта данных.

И, наконец, совсем специальный топик, точнее, класс топиков, начинающихся с символа «$». Это топики системной информации и управления сервером MQTT, стандарт строго ограничивает их применения – сервер должен препятствовать использованию таких топиков клиентами для обмена информацией.

Как бы подводя итоги – Pub-метаинформация (точный семантический «путь» к публикуемым данным) клиента MQTT должна соответствовать требованию well-formed UTF-8 string и не может содержать символов «#», «+» и «$», Sub-метаинформация (описание множества семантических «путей» требуемых данных) может содержать wildcards и символ «$» первым символом топика высшего уровня.

Пожалуй, последнее важное, что нужно к этому добавить – стандартом определено право MQTT-сервера на модификацию текста топиков (зачем и как – об этом позже).

Частичная симметричность (или Pub-симметричность) протокола MQTT означает, что и клиент, и сервер могут выступать «издателями», причём с помощью одинакового механизма. «Подписчиком» же может быть только клиент.

TBC
Откланиваюсь

Ready, set, buy! Посібник для початківців - як придбати Copilot для Microsoft 365

+77
голосов

Напечатать Отправить другу

Читайте также

кстати, ядро линукса обновилось до 4.0

 

Ukraine

 

  •  Home  •  Ринок  •  IТ-директор  •  CloudComputing  •  Hard  •  Soft  •  Мережі  •  Безпека  •  Наука  •  IoT