Как я чаще всего структурировал подобные системы:. Сокет – сервис, который держит WS / TCP / UDP / MQTT соединения, он существует отдельно, чтобы когда мы редеплоим или масштабируем сервисы с бизнес-логикой соеднинения не отваливались.. Ресивер – сервис обработки сообщений с основной бизнес-логикой.. Командер – опционально, но в IoT чаще всего нужен сервис, который мапит ваши команды в команды, которые будет понимать устройство и отправляет их.Сообщения приходят в Сокет, идут в Ресивер, он отправляет команды ответа Камендеру и тот отправляет сообщения через Сокет (очень CQRS-ный подход с раздлением потока чтения и записи)Какие полезные трюки важно помнить:. Сервисы должны общаться асинхронно (не ждать ответа) иначе вы рано или поздно будете попадать в dead lock всей системы.. Соответственно, все сообщения должны представлять собой "события" (event) – структуру описывающие произошедший факт с данными об этом факте ("ПользовательСоздалСообщение", "СообщениеУспешноОбработано", "СообщениеУспешноОтправлено", etc.). Сокет должен содержать минимум логики, чтобы его не приходилось часто редеплоить ИЛИ если вам больше важно скорость, тогда объединяем Сокет, Ресивер и Командер. Все сообщения стоит хранить персистентно (Kafka или БД). В Realtime системах максимально важны 2 фактора: скорость и линейный рост нагрузки при увеличение числа сообщений.Хочу обратить внимание именно на последний пункт: чаще всего, самым узким горшлышком вашей системы будет не язык программирования, не транспорт и не сеть, а обращения в БД.Во-первых, каждое обращение – это время, во-вторых, запросы к БД сложно батчить, потому что каждое сообщение процесситься независимо друг от друга, в-третьих, если у вас не master-master база у вас будет ограниченное число коннектов.Все это приводит к тому, что
увеличение числа сообщений в секунду экспоненциально увеличивает нагрузку.Чтобы сделать скорость обработки сообщений константной, а рост нагрузки линейным лучшим вариантом будет доставать нужные данные в момент старта сервиса (или прихода первого сообщения), класть их в память (или в кэш типа Redis), с каждым сообщением проводить измения данных прямо в памяти и время от времени синхронизировать данные с основной базойЗадача не из легких, но именно тут нам на помощь приходит паттерн "Акторы"Акторы очень хорошо описывают то, как максимально удобно и понятно структурировать логику подобного рода.Сообщение получилось итак слишком большим, поэтому продолжение в следующей части, а пока посмотрите видос про акторы, который я еле откопал:
https://www.youtube.com/watch?v=Fw-CXSG8KZE