Рекомендации по кодировке сообщений

Многие облачные приложения используют асинхронные сообщения для обмена информацией между компонентами системы. Важным аспектом обмена сообщениями является формат, используемый для кодирования полезных данных. После выбора технологии обмена сообщениями следующий шаг — определить, как кодируются сообщения. Существует множество вариантов, но правильный выбор зависит от вашего варианта использования.

В этой статье описаны некоторые аспекты.

Потребности обмена сообщениями

Обмен сообщениями между производителем и потребителем требует:

  • Форма или структура, определяющая полезную нагрузку сообщения.
  • Формат кодирования для представления полезной нагрузки.
  • Библиотеки сериализации для чтения и записи закодированного содержимого.

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

  • Какой наиболее эффективный тип данных?
  • Всегда ли нагрузка имеет определенные поля?
  • Имеют ли полезные данные одну запись или повторяющийся набор значений?

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

Потребитель должен понять эти решения, чтобы правильно читать входящие сообщения.

Для передачи сообщений производитель сериализует сообщение в формат кодирования. На принимающей стороне потребитель десериализует полезную нагрузку, чтобы получить доступ к данным. Этот процесс гарантирует, что обе сущности совместно используют одну и ту же модель. Пока форма остается неизменной, обмен сообщениями продолжается без каких-либо проблем. При изменении контракта формат кодирования должен быть способен обрабатывать изменения без нарушения потребителя.

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

Рекомендации по формату кодирования

Формат кодирования определяет, как набор структурированных данных представлен в виде байтов. Тип сообщения может повлиять на выбор формата. Сообщения, связанные с бизнес-транзакциями, скорее всего, содержат структурированные данные. Кроме того, может потребоваться получить структурированные данные позже для целей аудита. Для потока событий может потребоваться как можно быстрее прочитать последовательность записей и сохранить ее для статистического анализа.

При выборе формата кодирования следует учитывать следующие факторы.

Читаемость для человека

Кодировка сообщений может быть широко разделена на текстовые и двоичные форматы.

При кодировке на основе текста полезные данные сообщения используются в виде обычного текста, поэтому пользователь может проверить его без использования библиотек кода. Такой подход упрощает чтение и понимание данных. Форматы, доступные для чтения человеком, подходят для архивных данных. Так как человек может читать полезные данные, текстовые форматы проще отлаживать и отправлять в журналы для устранения ошибок.

Недостатком кодировки на основе текста является то, что полезная нагрузка, как правило, больше. Размер полезной нагрузки часто может быть сокращен с помощью процесса минификации при условии, что его можно преобразовать в удобочитаемую форму для человека по мере необходимости. Распространенные текстовые форматы — JSON и YAML.

Шифрование

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

Размер кодировки

Размер сообщения влияет на производительность сетевых входных и выходных данных по проводу. Двоичные форматы являются более компактными, чем текстовые форматы. Двоичные форматы требуют сериализации и десериализации библиотек. Полезные данные можно считывать только при декодировании.

Используйте двоичный формат, если вы хотите сократить объем проводных операций и ускорить передачу сообщений. Эта категория формата рекомендуется в сценариях, когда хранилище или пропускная способность сети является проблемой. Варианты двоичных форматов включают Apache Avro, буферы протокола Google (protobuf), MessagePack и краткое представление двоичного объекта (CBOR). Преимущества и минусы этих форматов описаны далее в разделе "Выбор форматов кодирования".

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

Для небинарных форматов процесс минификации удаляет ненужные пробелы и символы, сохраняя соответствие спецификации формата. Этот подход помогает уменьшить размер кодировки без изменения структуры. Оцените возможности вашего кодировщика для установки минификации по умолчанию. Например, JsonSerializerOptions.WriteIndented из System.Text.Json.JsonSerializer .NET управляет автоматическим сжатием при создании JSON-документа.

Понимание полезной нагрузки

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

Помеченные метаданные. В некоторых форматах кодировки, в частности JSON, поля помечены типом данных и идентификатором в тексте сообщения. Эти форматы самоописательные, так как их можно разобрать в формате словаря значений без ссылки на схему. Одним из способов понимания полей является запрос ожидаемых значений. Например, производитель отправляет полезные данные в ФОРМАТЕ JSON. Потребитель разбирает JSON-файл в словарь и проверяет наличие полей, чтобы понять передаваемое сообщение. Другой способ заключается в том, чтобы потребитель применял модель данных, которую предоставляет производитель. Например, если вы используете язык со статической типизацией, многие библиотеки сериализации JSON могут преобразовать строку JSON в типизированный класс.

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

  • Сохраните схему в виде преамбулы или заголовка в сообщении, но отдельно от полезной нагрузки.

  • Сохраните схему в внешнем хранилище.

Некоторые форматы кодирования определяют схему и используют средства, которые создают классы из схемы. Производитель и потребитель используют эти классы и библиотеки для сериализации и десериализации данных. Библиотеки также обеспечивают проверки совместимости между схемой записи и считывания. И protobuf, и Apache Avro следуют этому подходу. Ключевое отличие заключается в том, что protobuf имеет определение схемы, не зависящего от языка, и Avro использует компактный JSON. Другое различие заключается в том, что оба формата обеспечивают проверки совместимости между схемами чтения и записи.

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

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

Хранение схемы вместе с полезными данными создает больший размер кодировки и идеально подходит для периодических сообщений. Выберите этот подход, если передача небольших фрагментов байтов имеет решающее значение или ожидается последовательность записей. Затраты на обслуживание внешнего хранилища схем могут быть высокими.

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

Управление версиями схемы

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

  • Потребитель должен отслеживать и понимать изменения.

    Один из способов заключается в том, чтобы потребитель проверял все поля, чтобы определить, изменилась ли схема. Другой способ заключается в том, чтобы производитель опубликовал номер версии схемы с сообщением. Когда схема развивается, производитель увеличивает версию.

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

    Предположим, что поле добавляется в существующую схему. Если потребители, использующие новую версию, получают полезные данные в соответствии со старой версией, их логика может нарушиться, если они не могут игнорировать отсутствие нового поля. Теперь рассмотрим противоположный сценарий. Если поле удаляется в новой схеме, потребители, использующие старую схему, могут не считывать данные.

    Форматы кодирования, такие как Avro, предоставляют возможность определять значения по умолчанию. В предыдущем примере, если поле добавляется со значением по умолчанию, отсутствующее поле заполняется значением по умолчанию. Другие форматы, такие как protobuf, предоставляют аналогичные функции с помощью обязательных и необязательных полей.

Структура полезных данных

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

  • Массив/словарь/значение: Определяет записи, которые содержат значения в одном или многомерном массиве. Записи имеют уникальные пары ключ/значение. Модель может быть расширена для представления сложных структур. К некоторым примерам относятся JSON, Apache Avro и MessagePack.

    Этот макет подходит, если сообщения кодируются по отдельности с различными схемами. Если у вас несколько записей, объем данных может стать чрезмерно избыточным. Эта избыточность может привести к увеличению объема полезной нагрузки.

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

    CSV (значения, разделенные запятыми) — это базовый текстовый формат. Он представляет данные в виде последовательности записей с общим заголовком. Для двоичной кодировки Apache Avro имеет преамблирование, аналогичное заголовку CSV, но которое создает более компактный размер кодировки.

Поддержка библиотеки

Вместо собственной модели следует использовать известные форматы. Известные форматы поддерживаются через библиотеки, которые сообщество универсально поддерживает. В специализированных форматах требуются определенные библиотеки. Бизнес-логика может обойти некоторые варианты проектирования API, предоставляемые библиотеками.

Для формата на основе схемы выберите библиотеку кодирования, которая проверяет совместимость между схемой чтения и записи. Определенные библиотеки кодирования, такие как Apache Avro, ожидают, что потребитель будет указывать как схему записи, так и схему чтения перед десериализацией сообщения. Эта проверка гарантирует, что потребитель осведомлён о версиях схемы.

Взаимодействие

Выбор форматов может зависеть от конкретной рабочей нагрузки или экосистемы технологий.

Например:

  • Azure Stream Analytics имеет встроенную поддержку JSON, CSV и Avro. Когда рабочая нагрузка использует Stream Analytics, имеет смысл выбрать один из этих форматов.

  • JSON — это стандартный формат обмена для REST API HTTP. Если приложение получает полезные данные JSON от клиентов, а затем помещает их в очередь сообщений для асинхронной обработки, может потребоваться использовать JSON для обмена сообщениями вместо повторной кодирования в другом формате.

Это всего два примера рекомендаций по взаимодействию. Стандартизированные форматы обычно являются более совместимыми, чем пользовательские форматы. В текстовых опциях JSON является одним из наиболее совместимых.

Выбор форматов кодирования

Для представления и передачи данных используются следующие популярные форматы кодирования. Учитывайте аспекты перед тем как выбрать формат.

JSON (JavaScript Object Notation)

JSON — это открытый стандарт, с его форматом, определенным в рабочей группе разработчиков Интернета (IETF) в RFC 8259. JSON — это текстовый формат, который следует модели массива, словаря или значения.

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

Самое большое преимущество заключается в том, что она общедоступна. JSON — это наиболее совместимый формат кодирования и по умолчанию для многих служб обмена сообщениями.

Поскольку JSON является текстовым форматом, он не является эффективным для передачи данных по сети и неидеально подходит, когда важна экономия места при хранении. По возможности используйте методы минификации. Если вы возвращаете кэшированные элементы непосредственно клиенту через HTTP, хранение данных в формате JSON может сократить затраты на десериализацию из другого формата и последующую сериализацию в JSON.

Используйте JSON для сообщений с одной записью или для последовательности сообщений, в которых каждое сообщение имеет другую схему. Избегайте использования JSON для последовательности записей, например для данных временных рядов.

Существуют другие варианты JSON, такие как двоичный JSON (BSON). BSON — это двоичная кодировка, согласованная с MongoDB.

CSV

CSV — это текстовый табличный формат. Заголовок таблицы указывает поля. CSV хорошо подходит для сообщений, содержащих набор записей.

Недостатком CSV является отсутствие стандартизации. Существует несколько способов выражения разделителей, заголовков и пустых полей.

Буферы протокола

Protocol Buffers (или protobuf) — это формат сериализации, использующий строго типизированные файлы определения типов для определения схем в парах "ключ-значение". Затем эти файлы определения компилируются в классы, относящиеся к языку, которые используются для сериализации и десериализации сообщений.

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

Apache Avro

Apache Avro — это формат двоичной сериализации, который использует файл определения, аналогичный protobuf, но без шага компиляции. Вместо этого сериализованные данные всегда включают предварительную схему.

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

Apache Parquet

Apache Parquet — это формат файла хранилища столбцов, который обычно связан с Apache Hadoop и связанными платформами обработки данных.

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

MessagePack

MessagePack — это формат двоичной сериализации, предназначенный для сжатия передачи по проводу. MessagePack не имеет определения схемы и проверки типов. Этот формат не рекомендуется для массового хранения.

CBOR

CBOR (спецификация) — это двоичный формат, предоставляющий небольшой размер кодировки. Преимущество использования CBOR над MessagePack заключается в его соответствии стандартам IETF, указанным в RFC7049.

Дальнейшие действия