Компрессия данных

Природа передаваемых данных в STOMP-протоколе

STOMP поверх WebSocket работает с текстовыми или бинарными фреймами, каждый из которых включает заголовки и тело сообщения. Основная нагрузка в реальных приложениях приходится на payload, особенно при передаче JSON-структур, событийных потоков или телеметрии.

Типичный фрейм STOMP состоит из:

  • команды (SEND, MESSAGE, SUBSCRIBE и т.д.)
  • набора заголовков
  • тела сообщения (payload)
  • завершающего нулевого символа

При высокой частоте сообщений и значительных объёмах данных сетевой канал становится узким местом. В таких условиях компрессия перестаёт быть опциональной оптимизацией и превращается в обязательный слой транспортной эффективности.


Уровни компрессии в архитектуре STOMP.js

Сжатие данных в связке STOMP.js и WebSocket может быть реализовано на нескольких уровнях:

1. Уровень WebSocket (permessage-deflate) Наиболее распространённый механизм — расширение WebSocket-протокола permessage-deflate.

Он работает следующим образом:

  • клиент и сервер договариваются о поддержке расширения при handshake
  • каждый фрейм может сжиматься алгоритмом DEFLATE
  • сжатие применяется ко всему сообщению целиком

Преимущества:

  • прозрачность для STOMP.js
  • отсутствие изменений в бизнес-логике
  • высокая скорость декомпрессии

Ограничения:

  • невозможность частичной компрессии payload
  • дополнительная нагрузка на CPU при большом количестве мелких сообщений
  • зависимость от поддержки сервера

2. Уровень приложения (payload compression) Второй подход — явное сжатие данных перед передачей в STOMP SEND.

Чаще всего используются:

  • gzip
  • deflate
  • brotli (реже, из-за совместимости)

В этом случае STOMP.js передаёт уже сжатый бинарный или base64-encoded payload.

Пример логики:

  • сериализация объекта в JSON
  • сжатие массива байт
  • отправка через STOMP как binary body или строка

Преимущества:

  • полный контроль над алгоритмом
  • возможность оптимизации структуры данных перед сжатием
  • совместимость даже при отсутствии WebSocket compression extensions

Недостатки:

  • усложнение клиентской и серверной логики
  • необходимость явного декодирования
  • риск увеличения latency при неправильной настройке

Особенности STOMP.js при работе с бинарными данными

Современные реализации STOMP.js поддерживают передачу бинарных payload через ArrayBuffer или Uint8Array.

Это критично для эффективного сжатия:

  • исключается необходимость base64-кодирования
  • уменьшается размер передаваемого сообщения на ~33%
  • снижается нагрузка на CPU при сериализации

Типичная схема:

  1. объект → JSON.stringify
  2. JSON → Uint8Array
  3. Uint8Array → gzip (если используется)
  4. отправка через client.publish / send

На стороне получения выполняется обратная цепочка.


Стратегии выбора метода компрессии

Выбор механизма зависит от характера трафика.

Частые мелкие сообщения

  • предпочтителен permessage-deflate
  • payload compression часто неэффективен (сжатие не окупает CPU cost)

Причина: небольшие JSON-фреймы плохо сжимаются, а накладные расходы на алгоритм могут превышать выигрыш.


Редкие крупные сообщения

  • эффективен application-level gzip/brotli
  • возможно комбинирование с WebSocket compression

Такие сценарии включают:

  • выгрузку логов
  • синхронизацию состояния
  • массовые обновления данных

Реалтайм-потоки (события, телеметрия)

  • минимальная компрессия или отсутствие
  • оптимизация структуры данных важнее сжатия

Пример: вместо JSON с длинными ключами используются короткие идентификаторы полей.


Компрессия и STOMP заголовки

STOMP-заголовки сами по себе не сжимаются отдельно от тела сообщения. Однако их влияние на итоговый размер заметно при высокочастотных потоках.

Практика оптимизации включает:

  • сокращение ключей заголовков (например, correlation-id → cid)
  • отказ от избыточных метаданных
  • использование повторно применяемых подписок вместо передачи параметров в каждом сообщении

Влияние компрессии на latency и CPU

Сжатие — это всегда баланс между:

  • уменьшением сетевого трафика
  • увеличением вычислительной нагрузки

В STOMP.js этот баланс особенно заметен из-за событийной природы протокола.

Основные наблюдения:

  • permessage-deflate снижает bandwidth до 60–80% при JSON-данных
  • CPU overhead может увеличиваться на 5–25% в зависимости от частоты сообщений
  • при мобильных сетях выигрыш значительно выше, чем в локальных сетях

Комбинированные схемы компрессии

На практике часто применяется гибридный подход:

Схема 1: WebSocket compression + JSON

  • STOMP.js отправляет обычные JSON-сообщения
  • транспорт сжимает весь фрейм

Схема 2: pre-compression payload

  • данные сжимаются gzip перед отправкой
  • WebSocket дополнительно применяет permessage-deflate

Схема 3: selective compression

  • только крупные сообщения проходят gzip
  • мелкие отправляются без изменений

Проблемы и ограничения при использовании сжатия

Несмотря на эффективность, компрессия в STOMP.js может создавать ряд проблем:

  • увеличение задержек при burst-трафике
  • нестабильная эффективность для коротких сообщений
  • сложность отладки бинарных payload
  • несовместимость некоторых серверных брокеров с расширениями WebSocket
  • риск деградации производительности при неправильном threshold для сжатия

Практические паттерны оптимизации данных

Помимо классического сжатия, STOMP.js приложения часто используют дополнительные техники:

  • нормализация JSON (убирание null-полей)
  • дедупликация повторяющихся структур
  • использование числовых кодов вместо строковых ключей
  • батчинг сообщений перед отправкой
  • агрегация событий на стороне клиента

Эти методы иногда дают больший эффект, чем алгоритмическая компрессия.


Работа с брокерами сообщений

Эффективность сжатия зависит от конкретного брокера:

  • RabbitMQ STOMP plugin — поддержка WebSocket compression ограничена конфигурацией
  • ActiveMQ — гибкая настройка transport connectors
  • Apollo / Artemis — оптимизированная работа с бинарными потоками

В каждом случае важно учитывать, где именно происходит компрессия: на уровне брокера, транспорта или клиента STOMP.js.


Итоговая модель потока данных

В типичной архитектуре STOMP.js с компрессией цепочка выглядит так:

  • генерация события в приложении
  • сериализация данных
  • (опционально) application-level compression
  • передача через STOMP frame
  • WebSocket transport compression
  • передача по сети
  • декомпрессия на стороне сервера
  • обработка брокером или подписчиком

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