Формат avro что это
Работа с форматом AVRO в python — библиотека fastavro
В статье описывается использование формата сериализации AVRO в языке python, дается краткое описание AVRO-схемы с пояснениями наиболее неочевидных моментов, приводятся конкретные примеры кода на python. Намеренно исключены из рассмотрения вопросы эволюции схем (schema evolution), RPC и AVRO-IDL.
Все примеры приводятся с использованием библиотеки fastavro, которую автору пришлось заметно доработать для соответствия спецификации и совместимости с java реализацией.
Историческая справка
Почему AVRO, а не json, bson, msgpack, protobuf, ASN.1, thrift, yaml?
При декомпозиции монолитной системы возникла необходимость описать процедуру взаимодействия между микросервисами. Не долго выбирая между RabbitMQ и Kafka остановились на последней. Но вот над следующей задачей — выборе системы сериализации пришлось попотеть.
При выборе системы сериализации учитывались следующие требования:
Поддержка нескольких языков программирования
Основа нашей кодовой базы — python 2.7. При чем в дальнейшем хотелось бы чувствительные к производительности процессы перевести на другие языки.
Валидация данных при сериализации
В динамическом интерпретируемом питоне слишком просто случайно отправить «не те» данные. А в выбранной нами pub-sub модели кафки нам было очень важно обеспечить корректность входных данных в топике. Нужна была система позволяющая типизировать топики кафки.
Наша система активно оперирует типами Decimal, UUID и Datetime. Увы — известные форматы сериализации начиная ASN.1 и заканчивая msgpack в основном описывают сериализацию низкоуровневых типов (int\float\string\bytes) и не предлагают законченных решений для интересующих нас.
Исходя из этих соображений выбор пал на AVRO. Но внезапно оказалось (весна 2017) что не смотря на наличие поддержки логических типов в спецификации и JAVA билиотеки — ни в официальной реализации AVRO для python, ни в конкурирующей fastavto их просто проигнорировали. Пришлось добавлять самостоятельно.
Наиболее адекватный (а также самый быстрый) код оказался у fastavro, в результате было принято решение доработать эту библиотеку. Это стало первым моим опытом участия в opensource.
Что такое AVRO
AVRO это система сериализации данных, созданная в рамках проекта Hadoop. Данные сериализуются бинарный формат с помощью предварительно созданной json-схемы при чем для десериализации также требуется схема (возможно — другая).
Также AVRO позволят в рамках одного контейнера упаковать множество записей заданных единственной схемой, что позволяет эффективно передавать большие объемы данных, избегая свойственные другим форматам накладные расходы.
AVRO-схема
Я не стану подробно описывать правила построения схем, т.к. они изложены в официальной документации
Остановлюсь лишь на базовых вещах и совсем уж не очевидных моментах.
AVRO-схема представляет из себя JSON, описывающий сериализуемую\десериализуемую структуру данных. Типы данных могут быть:
Хотя вышеперечисленные логические типы уже давно являются стандартом в реляционных БД и современных языках программирования — библиотеки сериализации обходили их стороной, вынуждая сводить их к примитивным типам, к счастью в AVRO эта проблема решена.
Рассмотрим простую схему:
Схема начинается с объявления типа record с заданными name и namespace. Эти поля в первых строках будут использоваться в системах кодогенерации, не актуальных для питона, т.к. у нас схема будет обрабатываться динамически. Далее идет перечисление типов полей нашей записи.
Особый интерес представляет объявление поля datetime, т.к. оно содержит логический тип. Важно помнить, что логические типы следует задавать вложенными в описания типа поля.
Отдельного упоминания заслуживают логические типы Decimal (число с фиксированной точкой) и UUID.
Decimal требует дополнительных параметров — числа знаков в числе и числа знаков после запятой:
А UUID интересен тем, что в спецификации его нет, а реализация его есть. При чём довольно странно сделанная — UUID кодируется строкой.
Пришлось добавить в fastavro и такую реализацию.
Примеры работы с fastavro
Как прочитать из контейнера
Как записать в контейнер
Как сериализовать и десериализовать данные вне контейнера
Используется при передачи данных как сообщений.
Как подавить чтение логических типов
Теперь логический тип timestamp-millis будет читаться не в Datetime питона, а в long.
Как заранее прочитать схему
В fastavro предусмотрена функция acquaint_schema, которая считывает схему во внутренний репозиторий (бывают ещё и внешение, но это отдельная история).
и загрузив её с помощью acquaint_schema можно в дальнейшем использовать краткое описание типов :
Обратите внимание — имя типа при обращении включает его namespace types.decimal_18_6
Также это необходимо в отдельных не тривиальных случаях
Файл Avro
Apache Avro — это система сериализации данных. Avro предоставляет:
Конфигурация
Поведение источника данных Avro можно изменить с помощью различных параметров конфигурации.
Чтобы настроить сжатие при записи, задайте следующие свойства Spark:
Для Databricks Runtime 9,1 LTS и Databricks Runtime 9,1 LTS Photon и выше можно изменить поведение вывода схемы по умолчанию в Avro, указав параметр при чтении файлов. Если задано значение, то mergeSchema true схема будет определяться из набора файлов Avro в целевом каталоге и объединять их, а не определять схему чтения из одного файла.
поддерживаемые типы для типа Avro — > преобразование SQL Spark
Эта библиотека поддерживает чтение всех типов Avro. в нем используется следующее сопоставление типов Avro с типами SQL Spark:
Тип Avro | тип SQL Spark |
---|---|
boolean | BooleanType |
int | IntegerType |
long | LongType |
float | FloatType |
double | DoubleType |
Байты | BinaryType |
string | StringType |
запись | StructType |
enum | StringType |
array | ArrayType |
карта | MapType |
fixed | BinaryType |
union | См. раздел типы объединений. |
Типы объединения
Источник данных Avro поддерживает чтение union типов. Avro считает следующие три типа для union типов:
Логические типы
Источник данных Avro поддерживает чтение следующих логических типов Avro:
Логический тип Avro | Тип Avro | тип SQL Spark |
---|---|---|
дата | int | DateType |
Метка времени — | long | TimestampType |
Метка времени-Micros | long | TimestampType |
decimal | fixed | DecimalType |
Decimal | Байты | DecimalType |
Источник данных Avro игнорирует документы, псевдонимы и другие свойства, имеющиеся в файле Avro.
поддерживаемые типы для преобразования Spark SQL- > Avro
эта библиотека поддерживает запись всех типов SQL Spark в Avro. Для большинства типов сопоставление типов Spark с типами Avro является простым (например, IntegerType преобразуется в int ); ниже приведен список некоторых особых случаев.
тип SQL Spark | Тип Avro | Логический тип Avro |
---|---|---|
ByteType | int | |
ShortType | int | |
BinaryType | Байты | |
DecimalType | fixed | Decimal |
TimestampType | long | Метка времени-Micros |
DateType | int | дата |
тип SQL Spark | Тип Avro | Логический тип Avro |
---|---|---|
ByteType | fixed | |
StringType | enum | |
DecimalType | Байты | Decimal |
TimestampType | long | Метка времени — |
Примеры
Scala
В этом примере демонстрируется пользовательская схема Avro:
В этом примере демонстрируются параметры сжатия Avro:
В этом примере демонстрируются секционированные записи Avro:
В этом примере показано имя записи и пространство имен:
Python
SQL-код
чтобы запросить данные Avro в SQL, зарегистрируйте файл данных как таблицу или временное представление:
Записная книжка
В следующей записной книжке показано, как читать и записывать файлы Avro.
Protobuf vs Avro. Как сделать выбор?
В статье перечислены особенности двух популярных форматов сериализации, которые следует учитывать архитектору, выбирая один из них.
Размер и скорость
В сети можно найти сравнительные тесты форматов сериализации. Не стоит придавать значение конкретным числам, так как скорость сериализации/десериализации, как и размер получающихся двоичных данных, зависит от конкретной схемы данных и от реализации сериализатора. Отметим лишь, что авро и протобаф занимают лидирующие позиции в подобных тестах.
Преимущество aвро в том, что поля записи сохраняются одно-за-другим, без разделителей. Но, имея дело с авро, вам нужно где-то сохранять схему записанных данных. Она может быть прикреплена к сериализированным данным или же храниться отдельно (тогда к данным добавляется идентификатор схемы во внешнем хранилище).
Фишка протобaфа в том, что, при сериализации целых чисел, по-умолчанию, используется формат переменной длины (varint), который занимает меньше места для небольших положительных чисел. Протобаф добавляет в бинарный поток номер поля и его тип, что увеличивает итоговый размер. Также, если в сообщение входят поля типа запись (nested message в терминологии протобафа), предварительно нужно вычислить итоговый размер записи, что усложняет алгоритм сериализации и занимает дополнительное время.
В целом, можно сказать, что вы будете удовлетворены размером и скоростью обоих форматов. В большинстве случаев это не тот фактор, который будет определять ваш выбор.
UPD: Высоконагруженная система или обработка данных в реальном времени может стать тем случаем, когда стоит присмотреться к более специализированным кодекам (ветвь дискуссии).
Типы данных
Примитивные типы, представленные в обоих форматах: bool, string, int32(int), int64(long), float, double, byte[]. Протобаф также поддерживает uint32, uint64.
В протобафе, по-умолчанию, целые числа кодируются в формате varint, эффективном для небольших положительных чисел. Вы можете изменить это, указав : sint32, sint64, fixed32, fixed64, sfixed32, sixed64.
Из коллекций вам доступны массивы и отображения (map). Ключом в отображении должна быть строка (в случае протобафа также допускается целое число).
Оба формата поддерживают перечисления (enumerations).
Сложные типы конструируются с помощью алгебраического умножения (records в авро, message в протобафе) и сложения (union в авро, oneof в протобафе).
UPD: в протобафе nullable также можно задать обернув необходимый тип в message из одного поля. Еще есть экспериментальная поддержка ключевого слова optional, которое работает, как синтаксический сахар над oneof. Дискуссия на stackoverflow.
Оба формата поддерживают механизмы расширения системы типов (logical types в авро и well known types в протобафе). Таким образом обе схемы дополнительно поддерживают сериализацию даты и времени (timestamp) и продолжительности времени (duration).
Эволюция данных
Обе схемы поддерживают механизмы обратной совместимости (backward compatibility) за счет заполнения новых полей значениями по-умолчанию. В авро можно указать любое, допустимое значение, в протобафе это значение задано жестко, в зависимости от типа (0, пустая строка, false). В авро также поддерживаются альтернативные имена (aliases) для полей и именованных типов (record, enum, fixed). В протобафе имя поля не используется в двоичной сериализации, но номер поля не может быть изменен.
Для числовых типов, в авро допускаются только преобразования без потери (например int в long, float в double, но не наоборот). Протобаф более толерантен к изменению числовых типов и применяет правила преобразования, идентичные C++. Также протобаф допускает преобразования из bool в число и обратно, из целого числа в enum и обратно.
В случае, когда потребитель данных использует старую схему, а производитель более новую, важно, чтобы новый формат данных не сломал работу потребителя. Такое свойство схемы данных называется упреждающей совместимостью (forward compatibility).
Неизвестное поле в записи игнорируется обоими форматами.
Неизвестный вариант (case) в объединении (union) протобаф помечает признаком unknown. Авро же, в этом случае, выдает исключение и прерывает десериализацию.
Это серьезное ограничение авро. Если вы используете алгебраические типы данных (ADT), то авро, скорее всего, вам не подходит, так как не поддерживает упреждающую совместимость при добавлении нового варианта в объединение.
Представление в Json
Как авро, так и протобаф, поддерживают сериализацию в Json. Это может быть полезно, как для отладочных целей, так и для долгосрочного хранения данных (например, в MongoDB).
В случае протобафа, нарушится обратная совместимость, если вы поменяете название поля (на самом деле есть трюк, и вы можете переименовать поле один раз, использовав атрибут json_name для сохранения информации о прежнем имени поля). Авро же позволяет давать несколько альтернативных названий (aliases) полям.
Неприятным свойством авро является то, что массив байт (типы bytes, fixed) сохраняется в виде UTF16 строки. Это не только порождает визуальный мусор (псевдографика, переводы строк и т.п), но и может сделать Json нечитаемым, так как не все библиотеки корректно транслируют UTF16. Протобаф же сохраняет массив байт в base64.
Представление в формате Json не должно повлиять на ваш выбор, не забывайте только, что в случае протобафа, вы можете переименовать поле только один раз, а в случае авро, нужно проверить ваш стек на корректность обработки UTF16.
Влияние на архитектуру
Выбрав авро, вы должны будете решить, где хранить схему. В том случае, если вы работаете с большим количеством сообщений малого размера (например, отправляете сообщения через кафку), вам нужно хранить схемы данных в отдельном хранилище (например, использовать Schema Registry). Вам потребуется реализовать кеширование схем, что привнесет в вашу систему состояние (statefullness), будет забирать время на “прогрев” при запуске.
Если ваш язык программирования обладает динамической системой типов (например, python), то протобаф, с его требованием заранее задать типы всех полей, может стать для вас слишком обременительным. Авро же, наоборот, может стать хорошим решением, так как позволяет десериализировать данные “на лету”, зная лишь схему по которой эти данные были сохранены. Для случаев динамической типизации, в протобафе появился тип Any, но, согласно официального сайта, его поддержка в процессе разработки.
В обоих форматах есть возможность описать интерфейс для удаленного вызова процедур.
Протокол авро поддерживает синхронный вызов процедуры и вызов без ожидания ответа (one-way). Протокол включает в себя этап рукопожатия (handshake), в время которого стороны обмениваются схемами.
Сервис протобафа допускает как синхронный вызов, так и отправку потока данных (streaming) в обоих направлениях.
Прежде чем сделать выбор, убедитесь, что в вашем стеке существует реализация RPC, удовлетворяющая ваши потребности.
Kafka
Изначально схема данных в кафке описывалась с помощью авро. В настоящее время добавлена поддержка протобафа.
Hadoop
Национальная библиотека им. Н. Э. Баумана
Bauman National Library
Персональные инструменты
Apache Avro
Apache Avro — система сериализации данных, разработанная в рамках проекта Hadoop. Система использует JSON для определения структуры данных (схемы), которые сериализуются в компактный бинарный формат.
Содержание
Сравнение с другими системами
Avro имеет схожий функционал с такими системами как Thrift, Protocol Buffers, и т.д. Но имеет следующие фундаментальные отличия от этих систем:
Схема
Схема является описанием структуры данных с помощью JSON. Схема допускает как простые типы — (null, boolean, int, long, float, double, bytes, string), так и сложные составные типы (словари, массивы, перечисления и другие)
Пример схемы:
Контейнер
Контейнер состоит из:
Для блоков данных Avro может использовать две кодировки: бинарные данные и в формате JSON. Эффективнее использовать бинарную кодировку, которая быстрее и компактнее, но для отладки удобнее использовать человекочитаемый формат JSON
Сообщение
Протокол
Протокол описывается RPC интерфейс. Как и схема, протокол описывается через JSON и имеет следующие поля:
Avro IDL
В дополнение к JSON для определения схем и протоколов, Avro имеет экспериментальную поддержку альтернативного языка описания интерфейса (IDL), чей синтаксис больше похож на Java, C/C++ или Python
Сериализация и десериализация
Файл «users.avro» будет содержать схему в формате JSON и компактное двоичное представление данных [Источник 2] :
Avro может использоваться в связке с любым языком, для следующих языков уже есть API:
Пример работы
Формат avro что это
Avro – это линейно-ориентированный (строчный) формат хранения файлов Big Data, активно применяемый в экосистеме Apache Hadoop и широко используемый в качестве платформы сериализации.
Как устроен формат Avro для файлов Big Data: структура и принцип работы
Avro сохраняет схему в независимом от реализации текстовом формате JSON (JavaScript Object Notation), что облегчает ее чтение и интерпретацию как программами, так и человеком [1].
Файл Авро состоит из заголовка и блоков данных. Заголовок содержит:
Для блоков данных Avro может использовать компактную бинарную кодировку или человекочитаемый формат JSON, удобный для отладки.
В отличие от многих других форматов Big Data, столбцовых (RCFile, Apache ORC и Parquet) и линейно-ориентированных (Sequence, Map-File), Avro поддерживает эволюцию схем данных, обрабатывая изменения схемы путем пропуска, добавления или модификации отдельных полей. Авро не является строго типизированным форматом: информация о типе каждого поля хранится в разделе метаданных вместе со схемой. Благодаря этому для чтения сериализованной информации не требуется предварительное знание схемы [2]. О том, что такое сериализация и зачем нужны схемы данных, мы рассказывали здесь.
Авро обеспечивает богатую структуру данных, поддерживая следующие типы [3]:
Достоинства и недостатки формата Авро
Линейная структура данных формата Avro обеспечивает следующие преимущества [1]:
Еще стоит отметить, что независимая от реализации человекочитаемая JSON-схема данных обеспечивает поддержку множества языков программирования (C, C++, C#, Go, Haskell, Java, Python, Scala, другие скриптовые и ООП-языки), а также облегчает отладку в процессе разработки. Наконец, наличие широких возможностей описания объектов и событий, включая создание собственных схем данных, и совместимость с предыдущими версиями по мере развития данных с течением времени, делают формат Avro отличным вариантом для потоковых данных [3].
Тем не менее, по сравнению с колоночно-ориентированными форматами (RCFile, Apache ORC и Parquet) Авро свойственны следующие недостатки [4, 1]: