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

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

В этой статье описываются некоторые из особенностей.

Требования к обмену сообщениями

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

  • форма или структура, определяющая полезные данные сообщения;
  • формат кодирования для представления полезных данных;
  • библиотеки сериализации для чтения и записи закодированных полезных данных.

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

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

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

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

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

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

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

Ниже приведены некоторые моменты, которые следует учитывать при выборе формата кодирования.

Удобочитаемость

Форматы кодирования сообщений можно в целом разделить на следующие категории: текстовые и двоичные.

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

Их недостатком является увеличение объема полезных данных. Распространенным текстовым форматом является JSON.

Шифрование

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

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

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

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

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

Общие сведения о полезных данных

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

Помеченные тегами метаданные. В некоторых форматах кодирования, в частности 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

JSON — это открытый стандарт (IETF RFC8259). Это текстовый формат, который следует модели "массив/словарь/значение".

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

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

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

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

Существуют и другие разновидности JSON, такие как BSON. Это двоичное кодирование, согласованное для работы с MongoDB.

Значения с разделителями-запятыми (CSV)

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

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

Буферы протоколов (protobuf)

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

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

Apache Avro

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

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

MessagePack

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

CBOR

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

Следующие шаги