Перейти к контенту

Событийная архитектура для логистической компании

Миграция устаревшего монолита на событийную архитектуру. Внедрение MQTT для телеметрии транспорта, паттерна гарантированной доставки и защита учётной системы через антикоррупционный слой.

10k+ RPS
Пропускная способность телеметрии
< 100 мс
Внутренняя задержка обработки
Гарантия доставки
Семантика «как минимум один раз»
5x
Снижение сетевого трафика

Резюме

Миграция логистической платформы регионального транспортного оператора с монолитной PHP-архитектуры на событийно-ориентированную систему на базе стека Go/Kafka/MQTT.

Ключевые бизнес-результаты:

  • Пропускная способность: рост с 200 до 10 000+ RPS — запас для масштабирования парка
  • Операционные расходы: снижение затрат на мобильный трафик в 5 раз
  • Надёжность: переход от SLA 98% к 99.5%
  • Защита инвестиций: существующая учётная система (1С) сохранена, нагрузка на неё снижена

Контекст: Простой системы мониторинга транспорта напрямую влияет на операционную эффективность. Событийная архитектура исключает каскадные отказы, характерные для монолитных систем.


1. Проблематика: Анализ рисков Legacy-архитектуры

1.1 Исходное состояние системы

Заказчик эксплуатировал монолит на стеке LAMP (PHP 7.4 / MySQL 5.7). GPS-трекеры отправляли координаты прямыми HTTP-запросами в REST API, который синхронно записывал данные в основную БД.

1.2 Идентифицированные технические риски

Таблица 1. Матрица рисков Legacy-архитектуры

Категория рискаПроявлениеБизнес-последствия
Блокировки БДLock Wait Timeout при конкуренции запросовЗадержки в отображении на карте
Потеря данныхУтрата GPS-точек при разрыве соединенияНеполный трек маршрута
Thundering HerdПереподключение устройств после сбоя сетиПерегрузка системы
Vertical ScalingPHP-FPM: 20-30 МБ RAM на запросРост затрат на инфраструктуру

1.3 Количественная оценка нагрузки

Расчёт требуемой пропускной способности:

Частота опроса: 1 Гц (GPS + базовая телеметрия)
Текущий парк: N транспортных средств
Целевой рост: 3× (масштабирование парка)
 
Текущая нагрузка: ~3 000 событий/сек
Целевая нагрузка: ~10 000 событий/сек (с запасом)

Вывод: Синхронная модель исходного монолита (предел ~200 RPS) исчерпала лимит масштабирования. Требуется архитектурная трансформация.


2. Архитектурные решения

2.1 Принципы проектирования

Мы применили разделение потоков данных на Hot Path (телеметрия реального времени) и Cold Path (отчётность, синхронизация с учётной системой), реализовав паттерн Event-Driven Architecture.

FleetMQTTKafkaServicesDB
100%
Ctrl+Колесо или перетаскивание

Рис. 1. Высокоуровневая архитектура системы. Стрелки показывают направление потока данных.

2.2 Обоснование технологического стека

2.2.1 Выбор протокола: MQTT vs HTTP/REST

Таблица 2. Сравнительный анализ протоколов

КомпонентHTTP/RESTMQTT v5Экономия
Минимальный заголовок200-400 байт2 байта100-200×
TLS HandshakeНа каждый запросОднократно~300 мс/запрос
Payload encodingJSON (текст)Binary (Protobuf)3-5×
QoS механизмУровень приложенияВстроенный

Выбор протокола

Архитектурное решение
MQTT v5

Встроенный QoS, Keep-Alive соединения, минимальные накладные расходы (2 байта заголовок).

100-200× меньше накладных расходов
Экономия трафика
Нативная поддержка QoS
Отклонённый вариант
WebSocket

Отсутствие встроенного QoS — требуется реализация на уровне приложения.

Нет встроенного QoS
Дополнительная разработка механизмов доставки

2.2.2 Выбор языка: Go vs Альтернативы

Таблица 3. Сравнение runtime-характеристик

ПараметрPHP-FPMNode.jsGo
RAM на соединение20-30 МБ10-50 КБ2-8 КБ
GC Pause (p99)N/A5-20 мс< 1 мс
Макс. соединений/нода~1 000~50 000~100 000+

Выбор языка

Архитектурное решение
Go (Golang)

Goroutines с минимальным потреблением памяти (2-8 КБ на соединение), GC pause менее 1 мс.

Минимальное потребление памяти
Предсказуемая латентность
Нативная конкурентность
Отклонённый вариант
Node.js

Выше потребление памяти, event loop не оптимален для CPU-bound задач.

10-50 КБ на соединение
Event loop bottleneck

2.2.3 Выбор брокера: Kafka vs Альтернативы

Таблица 4. Сравнение брокеров сообщений

КритерийRabbitMQRedis StreamsApache Kafka
Пропускная способность~50k msg/s~100k msg/s~500k msg/s
ПерсистентностьОпциональноОграниченоDisk-based
ReplayНетОграниченоПолный

Выбор брокера сообщений

Архитектурное решение
Apache Kafka

Возможность повтора событий — при сбое можно «перепроиграть» поток телеметрии. Kafka хранит лог с Retention 7 дней.

Высокая пропускная способность
Полный replay по offset
Персистентность
Отклонённый вариант
RabbitMQ

Удаляет сообщение после ACK — replay невозможен.

Нет replay событий
Ниже пропускная способность

3. Механики надёжности

3.1 Transactional Outbox Pattern

Проблема Dual Write: При обновлении статуса заказа сервис должен (1) записать в БД и (2) отправить событие в Kafka. Если БД обновится, а Kafka-publish упадёт — системы рассинхронизируются.

ServicePGCDCKafka TX WAL
100%
Ctrl+Колесо или перетаскивание

Рис. 2. Паттерн Transactional Outbox с CDC. Debezium читает WAL таблицы outbox_events и гарантирует доставку событий в Kafka.

3.2 Anti-Corruption Layer (ACL)

Проблема Legacy Integration: Прямое подключение новых сервисов к Legacy БД приводит к "протеканию" технического долга.

KafkaACLCB1C
100%
Ctrl+Колесо или перетаскивание

Рис. 3. Антикоррупционный слой для защиты учётной системы. Circuit Breaker предотвращает каскадный отказ при деградации 1С.

Ключевые механизмы ACL:

  1. Batching: Группировка событий снижает нагрузку на учётную систему
  2. Rate Limiting: Контролируемая скорость записи
  3. Circuit Breaker: При проблемах с 1С — остановка записи, накопление в Kafka

3.3 Store-and-Forward на устройствах

Проблема: Транспорт может находиться в зоне без покрытия. Без локальной буферизации данные теряются.

Решение: Телематические устройства реализуют паттерн Store-and-Forward:

  1. Локальный буфер — встроенная память на устройстве
  2. Очередь с приоритетом — при восстановлении связи сначала отправляются критические события (тревоги)
  3. Дедупликация на сервере — каждое событие содержит уникальный ID

3.4 Идемпотентность обработки

При использовании MQTT QoS 1 и Kafka возможны дубликаты сообщений. Все консьюмеры реализуют идемпотентную обработку через Redis SetNX с TTL.


4. Результаты и метрики

4.1 Сравнительный анализ производительности

Таблица 5. Ключевые метрики: Legacy vs EDA

МетрикаLegacy MonolithEDA (Go/Kafka/MQTT)Улучшение
Throughput200 RPS10 000+ RPS50×
Latency (p50)2-5 сек100-200 мс20×
Потеря данных2-5% при сбояхGuaranteed Delivery
1С CPU Load90%+15-20%
SLA98%99.5%
Сетевой трафикBaseline-80%

4.2 Бизнес-результаты

  • Масштабирование: система готова к росту парка в 3 раза без изменения архитектуры
  • Экономия трафика: снижение затрат на мобильную связь
  • Надёжность: сокращение времени простоя

5. Стратегия миграции: Strangler Fig

Миграция выполнялась поэтапно без остановки операций:

Фаза 1 — Shadow Mode (3 недели):

  • Развёртывание параллельного стека Go/MQTT/Kafka
  • Dual-write: устройства отправляют данные в обе системы
  • Валидация данных

Фаза 2 — Read Path Migration (4 недели):

  • Dashboards переключены на чтение из Kafka/ClickHouse
  • Legacy остаётся System of Record

Фаза 3 — Write Path Migration (4 недели):

  • Постепенное переключение устройств на MQTT
  • ACL синхронизирует данные в Legacy

Фаза 4 — Завершение (2 недели):

  • Отключение HTTP-ingestion в PHP

6. Заключение и рекомендации

Переход на событийно-ориентированную архитектуру с использованием Go/Kafka/MQTT — обоснованный выбор для логистических платформ с требованиями к масштабируемости.

Ключевые выводы:

  1. MQTT обеспечивает значительное снижение трафика — критично для мобильных сетей
  2. Kafka предоставляет необходимый запас производительности и гарантии доставки
  3. Go оптимален для высококонкурентных сценариев IoT
  4. Transactional Outbox и ACL — обязательные паттерны для безопасной интеграции с Legacy

Рекомендация: Данная архитектура применима к проектам модернизации систем мониторинга транспорта с требованиями к обработке телеметрии и интеграции с существующими учётными системами.

Событийная архитектура для логистической компании | СОФТЭНК | Софтэнк