Предлагаем вашему вниманию проектную работу Артема Данильченко, выпускника курса «Highload Architect«.
Цель моей проектной работы — создать базовую архитектуру платформы для сбора, обработки и хранения данных от IoT-устройств. Данная платформа должна отвечать следующим требованиям:
- поддержка различных протоколов транспортного уровня;
- поддержка различного набора информационных протоколов сбора данных от устройств;
- управление потоками данных внутри системы;
- интеграции с внешними системами и API;
- возможность создания Web-интерфейса для отображения данных.
Начало проектирования
Для снижения связности системы проектирование будет вестись с использованием подхода построения микросервисной архитектуры. Отличительными чертами данной архитектуры являются масштабируемость, адаптируемость и эволюционность.
Первый этап. Цифровой портрет IoT-устройства
Будем считать, что наше «сферическое IoT-устройство в вакууме» будет установлено на беспилотном комбайне или тракторе (например фирмы «Ростсельмаш») и передает следующий набор параметров:
— свой уникальный идентификатор. Для простоты считаем, что идентификатор уникален и задается в прошивке устройства или при его первой инициализации/регистрации в сети;
— геокоординаты и пространственные данные — широта и долгота, скорость и направление движения;
— системное время;
— техническое состояние устройства — заряд аккумулятор, уровень сигнала сети, уровень топлива, уровень масла, загруженность бункера, процент износа рабочих узлов и т. д.;
— счетчик переданных пакетов данных.
Особо стоит обратить внимание на то, что IoT-устройству придется работать в условиях плохого или нестабильного канала передачи данных. А это значит, что необходимо максимально сжимать пакет полезных данных для передачи и использовать различные информационные протоколы.
Второй Этап. Проектирование сервера сбора данных
Сервер сбора данных должен предоставлять следующие возможности:
- Поддержка TCP и UDP-протоколов транспортного уровня.
- Поддержка протоколов MQTT и LoRaWAN.
- Способность выдерживать несколько тысяч одновременных сетевых подключений.
- Быть экономичным в части потребления ресурсов.
- Скорость разработки и простота поддержки.
Для разработки такого сервера лучше всего подходят языки типа С, С++, Golang, Rust. Поскольку я несколько последних лет пишу исключительно на Golang, то для реализации MVP курсового проекта был выбран Golang.
Следующая проблема, которая возникает при реализации системы, — это источники данных. Не всегда есть под рукой нужные устройства или же их недостаточное количество. Выходом из такой ситуации является разработка своих программных имитаторов.
Программные имитаторы позволяют решить следующие проблемы:
- сэкономить бюджет проекта, не тратиться на закупку большого числа устройств;
- создавать различные варианты нагрузки (плавное увеличение, DDOS, пиковая нагрузка);
- упрощает поддержку и тестирование различных протоколов информационного обмена;
- позволяет моделировать отказы и нештатные ситуации.
В курсовом проекте я сделал простую реализацию tcp сервера и имитатора клиента, которые производили обмен открытой ASCII-строкой со списком параметров.
###ID=1234235345&CNT=1&STM=220828003254&LAT=47.257178&LON=39.7633771***
Для имитации плохого канала связи между имитатором устройства и сервером был развернут прокси «ToxyProxy» (https://github.com/Shopify/toxiproxy).
Применение этого инструмента позволяет смоделировать задержки в канале передачи данных, timeout сервера, ограничение пропускной способности и т. д.
Итак, в качестве первого сегмента нашей системы мы можем нарисовать вот такую архитектурную схему:
Третий Этап. Накопление и передача данных для вторичной обработки
После приема данных сервером их необходимо передать на дальнейшую обработку. Но тут возникает ряд ограничений:
- потребителями данных может быть не одна система;
- данные поступают неравномерно и в пиковые моменты возможна задержка в обработке;
- должна быть возможность маршрутизация трафика внутри системы.
На помощь приходит один из брокеров сообщений : ZeroMQ, RabbitMQ, NATS.
Для своего проекта я выбрал NATS ( https://docs.nats.io/ ). Мой выбор обоснован следующими доводами:
- написан на Golang. Не требует дополнительных библиотек и фреймворков. Легко разворачивается на любой системе, даже без Docker;
- поддержка механизмов Publish-Subscribe, Request-Reply, Streaming, Key/Value Store, MQTT;
- простая маршрутизация сообщений;
- у меня есть экспертиза по построению систем на базе NATS.
Как было сказано выше, брокер сообщений выступает связующим звеном для различных подсистем платформы:
- Подсистема обработки входяших сообщений IoT-устройств. В задачи данной системы входит распаковка входящих данных, сохранение их в БД и передача в другие системы для вторичной обработки. Реализация выполнена на Golang + PostgreSQL.
- Подсистема управления устройствами. Отвечает за управление настройками устройств, формирование и передачу новых настроек функционирования устройства (например — частота выхода на связь).
- Подсистема уведомлений. Отвечает за централизованную рассылку оповещений по изменению состояния или параметров устройств или объекта наблюдения.
- Подсистема геопозиционирования и картографии. Подсистема для взаимодействия с внешними системами картографии, геопозиционирования, топопривязки. OpenStreetMap, YandexMap, ArcGIS. Так как геоданные являются редкоизменяемыми с долгой актуальностью, для снижения нагрузки на внешние системы и увеличения скорости запросов можно поставить Reddis или аналоги для кэширования данных от внешних систем.
И теперь архитектура платформы принимает вот такой вид:
Четвертый этап. Web-интерфейс и внешнее API
Для реализации доступа к данным платформы предлагается сделать 2 API.
1. Public API. Программный интерфейс доступа для сторонних систем и сторонних разработчиков. Может быть реализован как обычный REST API с авторизацией доступа через jwt-token. Для защиты платформы от от ddos необходимо использовать rate limiter.
2. Internal API. Внутренний API используется для обеспечения работы web-компонентов IoT-платформы. Например — мобильный клиент или личный кабинет с доступом через web-браузер. Оптимальным решением для организации работы будет использование gRPC с сериализацией данных через protobuf.
Данный подход позволит снизить объем трафика, обеспечить обратную совместимость и расширяемость API.
Любые запросы к серверу должны в обязательном порядке проходить через балансировщик нагрузки. По возможности, данные, которые запрашиваются из БД, должны кэшироваться.
В качестве простой реализации GUI я сделал вывод координат IoT-устройств на карту. Для этого потребовалось написать простой web-сервер на go.
5 этап. Мониторинг
Для мониторинга системы можно применять elk+ prometuse.
Для трассировки запросов — opentelemetry.
В рамках MVP реализация не выполнялась.
Итог:
Конечный вариант архитектуры проекта: