Руководство по Apache Avro

Руководство по Apache Avro

1. обзор

Сериализация данных - это метод преобразования данных в двоичный или текстовый формат. Для этой цели доступно несколько систем. Apache Avro - одна из таких систем сериализации данных.

Avro is a language independent, schema-based data serialization library. Он использует схему для выполнения сериализации и десериализации. Кроме того, Avro использует формат JSON для указания структуры данных, что делает ее более мощной.

В этом руководстве мы узнаем больше о настройке Avro, Java API для выполнения сериализации и сравним Avro с другими системами сериализации данных.

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

2. Апач Авро

Avro - это независимая от языка библиотека сериализации. Для этого Avro использует схему, которая является одним из основных компонентов. Этоstores the schema in a file for further data processing.

Avro лучше всего подходит для обработки больших данных. Он довольно популярен в мире Hadoop и Kafka из-за более быстрой обработки.

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

Чтобы использовать Avro для сериализации, нам нужно выполнить шаги, указанные ниже.

3. Постановка задачи

Начнем с определения классаAvroHttRequest, который мы будем использовать в наших примерах. Класс содержит как простые, так и сложные атрибуты типа:

class AvroHttpRequest {

    private long requestTime;
    private ClientIdentifier clientIdentifier;
    private List employeeNames;
    private Active active;
}

ЗдесьrequestTime - примитивное значение. ClientIdentifier - еще один класс, представляющий сложный тип. У нас также естьemployeeName, который снова является сложным типом. Active - это перечисление, описывающее, активен данный список сотрудников или нет.

Наша цель - сериализовать и десериализовать классAvroHttRequest с помощью Apache Avro.

4. Типы данных Avro

Прежде чем продолжить, давайте обсудим типы данных, поддерживаемые Avro.

Avro поддерживает два типа данных:

  • Тип примитива: Avro поддерживает все типы примитивов. Мы используем имя типа примитива для определения типа данного поля. Например, значение, содержащееString, должно быть объявлено как \ {«type»: «string»} в схеме.

  • Сложный тип: Avro поддерживает шесть видов сложных типов: записи, перечисления, массивы, карты, объединения и фиксированные

Например, в нашей постановке задачиClientIdentifier - это запись.

В этом случае схемаClientIdentifier должна выглядеть так:

{
   "type":"record",
   "name":"ClientIdentifier",
   "namespace":"com.example.avro",
   "fields":[
      {
         "name":"hostName",
         "type":"string"
      },
      {
         "name":"ipAddress",
         "type":"string"
      }
   ]
}

5. Использование Avro

Для начала давайте добавим зависимости Maven, которые нам понадобятся, в наш файлpom.xml.

Мы должны включить следующие зависимости:

  • Apache Avro - основные компоненты

  • Компилятор - Apache Avro Компиляторы для Avro IDL и Java APIT для Avro

  • Инструменты - которые включают инструменты и утилиты командной строки Apache Avro

  • Плагин Apache Avro Maven для проектов Maven

В этом руководстве мы используем версию 1.8.2.

Однако всегда рекомендуется найти последнюю версию наMaven Central:


    org.apache.avro
    avro-compiler
    1.8.2


    org.apache.avro
    avro-maven-plugin
    1.8.2

После добавления зависимостей maven следующие шаги будут следующими:

  • Создание схемы

  • Чтение схемы в нашей программе

  • Сериализация наших данных с помощью Avro

  • Наконец, десериализовать данные

6. Создание схемы

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

  • Type-, который описывает тип схемы, будь то сложный тип или примитивное значение

  • Namespace-, который описывает пространство имен, которому данная схема принадлежит

  • Name - имя схемы

  • Fields-, который сообщает о полях, связанных с данной схемой. Fields can be of primitive as well as complex type.

Одним из способов создания схемы является написание представления JSON, как мы видели в предыдущих разделах.

Мы также можем создать схему, используяSchemaBuilder, что, несомненно, является лучшим и эффективным способом ее создания.

6.1. SchemaBuilder Утилита

Классorg.apache.avro.SchemaBuilder полезен для создания схемы.

Прежде всего, давайте создадим схему дляClientIdentifier:

Schema clientIdentifier = SchemaBuilder.record("ClientIdentifier")
  .namespace("com.example.avro")
  .fields().requiredString("hostName").requiredString("ipAddress")
  .endRecord();

Теперь давайте воспользуемся этим для создания схемыavroHttpRequest:

Schema avroHttpRequest = SchemaBuilder.record("AvroHttpRequest")
  .namespace("com.example.avro")
  .fields().requiredLong("requestTime")
  .name("clientIdentifier")
    .type(clientIdentifier)
    .noDefault()
  .name("employeeNames")
    .type()
    .array()
    .items()
    .stringType()
    .arrayDefault(null)
  .name("active")
    .type()
    .enumeration("Active")
    .symbols("YES","NO")
    .noDefault()
  .endRecord();

Здесь важно отметить, что мы назначилиclientIdentifier в качестве типа для поляclientIdentifier. В этом случаеclientIdentifier, используемый для определения типа, - это та же схема, которую мы создали ранее.

Позже мы можем применить методtoString, чтобы получить структуруJSON дляSchema.

Schema files are saved using the .avsc extension. Давайте сохраним нашу сгенерированную схему в файл“src/main/resources/avroHttpRequest-schema.avsc”.

7. Чтение схемы

Чтение схемы составляет примерноcreating Avro classes for the given schema. После создания классов Avro мы можем использовать их для сериализации и десериализации объектов.

Существует два способа создания классов Avro:

  • Программное создание классов Avro: классы могут быть созданы с использованиемSchemaCompiler. Есть пара API, которые мы можем использовать для генерации классов Java. Мы можем найти код для генерации классов на GitHub.

  • Использование Maven для создания классов

У нас есть один плагин Maven, который хорошо выполняет свою работу. Нам нужно включить плагин и запуститьmvn clean install.

Давайте добавим плагин в наш файлpom.xml:


    org.apache.avro
    avro-maven-plugin
    ${avro.version}
        
            
                schemas
                generate-sources
                
                    schema
                    protocol
                    idl-protocol
                
                
                    ${project.basedir}/src/main/resources/
                    ${project.basedir}/src/main/java/
                
            
        

8. Сериализация и десериализация с Avro

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

Avro поддерживает два формата сериализации данных: формат JSON и двоичный формат.

Сначала мы сосредоточимся на формате JSON, а затем обсудим двоичный формат.

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

DatumWriter<T>: Мы должны использовать это для записи данных в заданную схему. В нашем примере мы будем использовать реализациюSpecificDatumWriter, однако уDatumWriter есть и другие реализации. Другие реализации:GenericDatumWriter, Json.Writer, ProtobufDatumWriter, ReflectDatumWriter, ThriftDatumWriter.

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

DatumReader<D>: Единый интерфейс для десериализации. Опять же, у него есть несколько реализаций, но в нашем примере мы будем использоватьSpecificDatumReader. Другие реализации -GenericDatumReader, Json.ObjectReader, Json.Reader, ProtobufDatumReader, ReflectDatumReader, ThriftDatumReader.

Decoder: Декодер используется при десериализации данных. Decoderfactory предоставляет два типа декодеров: двоичный декодер и декодер JSON.

Затем давайте посмотрим, как сериализация и десериализация происходят в Avro.

8.1. Сериализация

Мы возьмем пример классаAvroHttpRequest и попробуем сериализовать его с помощью Avro.

Прежде всего, сериализуем его в формате JSON:

public byte[] serealizeAvroHttpRequestJSON(
  AvroHttpRequest request) {

    DatumWriter writer = new SpecificDatumWriter<>(
      AvroHttpRequest.class);
    byte[] data = new byte[0];
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    Encoder jsonEncoder = null;
    try {
        jsonEncoder = EncoderFactory.get().jsonEncoder(
          AvroHttpRequest.getClassSchema(), stream);
        writer.write(request, jsonEncoder);
        jsonEncoder.flush();
        data = stream.toByteArray();
    } catch (IOException e) {
        logger.error("Serialization error:" + e.getMessage());
    }
    return data;
}

Давайте посмотрим на тестовый пример для этого метода:

@Test
public void whenSerialized_UsingJSONEncoder_ObjectGetsSerialized(){
    byte[] data = serealizer.serealizeAvroHttpRequestJSON(request);
    assertTrue(Objects.nonNull(data));
    assertTrue(data.length > 0);
}

Здесь мы использовали методjsonEncoder и передали ему схему.

Если мы хотим использовать двоичный кодировщик, нам нужно заменить методjsonEncoder() наbinaryEncoder():

Encoder jsonEncoder = EncoderFactory.get().binaryEncoder(stream,null);

8.2. Десериализация

Для этого мы будем использовать вышеупомянутые интерфейсыDatumReader иDecoder.

Поскольку мы использовалиEncoderFactory для полученияEncoder,, аналогично мы будем использоватьDecoderFactory для получения объектаDecoder.

Давайте десериализуем данные в формате JSON:

public AvroHttpRequest deSerealizeAvroHttpRequestJSON(byte[] data) {
    DatumReader reader
     = new SpecificDatumReader<>(AvroHttpRequest.class);
    Decoder decoder = null;
    try {
        decoder = DecoderFactory.get().jsonDecoder(
          AvroHttpRequest.getClassSchema(), new String(data));
        return reader.read(null, decoder);
    } catch (IOException e) {
        logger.error("Deserialization error:" + e.getMessage());
    }
}

И давайте посмотрим на тестовый пример:

@Test
public void whenDeserializeUsingJSONDecoder_thenActualAndExpectedObjectsAreEqual(){
    byte[] data = serealizer.serealizeAvroHttpRequestJSON(request);
    AvroHttpRequest actualRequest = deSerealizer
      .deSerealizeAvroHttpRequestJSON(data);
    assertEquals(actualRequest,request);
    assertTrue(actualRequest.getRequestTime()
      .equals(request.getRequestTime()));
}

Точно так же мы можем использовать двоичный декодер:

Decoder decoder = DecoderFactory.get().binaryDecoder(data, null);

9. Заключение

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

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

И последнее, но не менее важное: Avro имеет отличную связь с широким спектром языков программирования, что дает ему преимущество.

Как всегда, код можно найтиover on GitHub.