Почему меняется размер закодированного сообщения
Перейти к содержимому

Почему меняется размер закодированного сообщения

Почему ascii и utf-8 тексты имеют разную длину?

hint000

— нонсенс. Если уж файл бинарный, то к нему неприменимо понятие «кодировка». И уточните, каким способом копируете, пока довольно туманно сформулировано.

Upd. вообще для ответа на ваш вопрос достаточно сделать побайтовое сравнение (есть программки), сразу будет видно отличия. Подозреваю, что дело в CR LF.

SagePtr

SagePtr

  • Facebook
  • Вконтакте
  • Twitter

В UTF-8 символы соответствующие ASCII кодируются одним октетом, но символы других кодовых страниц — различным количеством октет (от 2 до 4х в настоящее время), например кириллические символы или символы специфичные для европейских языков — 2мя октетами.

В ANSI-кодировках символы всегда кодируются одним октетом, и ANSI-кодировка может содержать не только ASCII-символы.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Используйте двоичный формат, если вы хотите сократить нагрузку на сеть и ускорить передачу сообщений. Эту категорию формата рекомендуется применять в сценариях, где важна пропускная способность хранилища или сети. Вариантами двоичных форматов являются 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 — это открытый стандарт (IETF RFC8259). Это текстовый формат, который следует модели «массив/словарь/значение».

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

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

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

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

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

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

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

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

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

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

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

Apache Avro

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

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

MessagePack

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

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

Почему данные в кодировке base64 так плохо сжимаются?

Я недавно сжимал некоторые файлы и заметил, что данные в кодировке base64 сжимаются очень плохо. Вот один пример:

  • Исходный файл: 429,7 Мбайт
  • сжать через xz -9 :
    13,2 MiB / 429,7 MiB = 0,031 4,9 MiB/s 1:28
  • base64 его и сжать через xz -9 :
    26,7 MiB / 580,4 MiB = 0,046 2,6 MiB/s 3:47
  • base64 исходный сжатый файл xz:
    17,8 MiB почти мгновенно = ожидаемое 1.33x увеличение размера

Итак, можно наблюдать следующее:

  • xz сжимает очень хорошо ☺
  • данные в кодировке base64 плохо сжимаются, они в 2 раза больше, чем незашифрованный сжатый файл
  • base64-then-compress значительно хуже и медленнее, чем compress-then-base64

Как это может быть? Base64 — это обратимый алгоритм без потерь, почему он так сильно влияет на сжатие? (Я тоже пробовал с gzip, с аналогичными результатами).

Я знаю, что нет смысла использовать base64, а затем сжимать файл, но в большинстве случаев никто не контролирует входные файлы, и я бы подумал, что, поскольку фактическая плотность информации (или как там ее называют ) файла в кодировке base64 будет почти идентичен некодированной версии и, следовательно, будет аналогичным образом сжимаемым.

Большинство общих алгоритмов сжатия работают с однобайтовой детализацией .

Рассмотрим следующую строку:

  • Алгоритм Run-Length-Encoding скажет: «это 4 ‘X’, затем 4 ‘Y’, затем 4 ‘X’, а затем 4 ‘Y’».
  • Алгоритм Лемпеля-Зива скажет: «Это строка« XXXXYYYY », за которой следует такая же строка: давайте заменим вторую строку ссылкой на первую».
  • Алгоритм кодирования Хаффмана скажет: «В этой строке всего 2 символа, поэтому я могу использовать только один бит на символ».

Теперь закодируем нашу строку в Base64. Вот что мы получаем:

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

Например, строка нашего примера начинается с группы из трех байтов, равных 0x58 в шестнадцатеричном формате (код ASCII символа «X»). Или в двоичном формате: 01011000. Применим кодировку Base64:

По сути, шаблон «в 3 раза больше байта 0x58», который был очевиден в исходном потоке данных, больше не очевиден в потоке закодированных данных, потому что мы разбили байты на 6-битные пакеты и сопоставили их с новыми байтами, которые теперь кажутся быть случайным.

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

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

Это еще более верно для шифрования: сначала сжать, а потом зашифровать.

РЕДАКТИРОВАТЬ — Примечание о LZMA

Как заметил MSalters, LZMA, который использует xz, работает с битовыми потоками, а не с байтовыми потоками.

Тем не менее, этот алгоритм также будет страдать от кодирования Base64, что по существу согласуется с моим предыдущим описанием:

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

Почему русские символы занимают два байта в utf-8, если они входят в диапазон от 128 до 255?

А при индексации русской строки символы занимают 16 бит, хотя в расширенной таблице ascii они вполне помещаются в 8 бит.

Потому, что они не входят в диапазон от 128 до 256 в UFT8.

Они входят в этот диапазон в однобайтовых кодировках типа CP1251 или CP866.

Для символов Юникода с номерами от U+0000 до U+007F (занимающими один байт c нулём в старшем бите) кодировка UTF-8 полностью соответствует 7-битной кодировке US-ASCII.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *