Guia para Apache Avro
1. Visão geral
A serialização de dados é uma técnica de conversão de dados em formato binário ou de texto. Existem vários sistemas disponíveis para esse fim. Apache Avro é um desses sistemas de serialização de dados.
Avro is a language independent, schema-based data serialization library. Ele usa um esquema para executar serialização e desserialização. Além disso, o Avro usa um formato JSON para especificar a estrutura de dados que o torna mais poderoso.
Neste tutorial, vamos explorar mais sobre a configuração do Avro, a API Java para realizar a serialização e uma comparação do Avro com outros sistemas de serialização de dados.
Vamos nos concentrar principalmente na criação de esquemas, que é a base de todo o sistema.
2. Apache Avro
Avro é uma biblioteca de serialização independente de idioma. Para fazer isso, o Avro usa um esquema que é um dos componentes principais. Éstores the schema in a file for further data processing.
O Avro é o mais adequado para o processamento de Big Data. É muito popular no mundo Hadoop e Kafka por seu processamento mais rápido.
O Avro cria um arquivo de dados onde mantém os dados junto com o esquema em sua seção de metadados. Acima de tudo, ele fornece uma estrutura de dados rica que o torna mais popular do que outras soluções semelhantes.
Para usar o Avro para serialização, precisamos seguir as etapas mencionadas abaixo.
3. Declaração do Problema
Vamos começar definindo uma classe chamadaAvroHttRequest que usaremos em nossos exemplos. A classe contém atributos de tipo primitivo e complexo:
class AvroHttpRequest {
private long requestTime;
private ClientIdentifier clientIdentifier;
private List employeeNames;
private Active active;
}
Aqui,requestTime é um valor primitivo. ClientIdentifier é outra classe que representa um tipo complexo. Também temosemployeeName, que é novamente um tipo complexo. Active é um enum para descrever se a lista de funcionários fornecida está ativa ou não.
Nosso objetivo é serializar e desserializar a classeAvroHttRequest usando Apache Avro.
4. Tipos de dados Avro
Antes de prosseguir, vamos discutir os tipos de dados suportados pelo Avro.
O Avro suporta dois tipos de dados:
-
Tipo primitivo: O Avro suporta todos os tipos primitivos. Usamos o nome do tipo primitivo para definir um tipo de um determinado campo. Por exemplo, um valor que contém umString deve ser declarado como \ {“tipo”: “string”} no Esquema
-
Tipo complexo: O Avro suporta seis tipos de tipos complexos: registros, enumerações, matrizes, mapas, uniões e unidades fixas.
Por exemplo, em nossa declaração de problema,ClientIdentifier é um registro.
Nesse caso, o esquema paraClientIdentifier deve ser semelhante a:
{
"type":"record",
"name":"ClientIdentifier",
"namespace":"com.example.avro",
"fields":[
{
"name":"hostName",
"type":"string"
},
{
"name":"ipAddress",
"type":"string"
}
]
}
5. Usando o Avro
Para começar, vamos adicionar as dependências do Maven que precisaremos ao nosso arquivopom.xml.
Devemos incluir as seguintes dependências:
-
Apache Avro - componentes principais
-
Compiler - Compiladores Apache Avro para Avro IDL e Avro Java APIT específico
-
Ferramentas - que inclui ferramentas e utilitários de linha de comando Apache Avro
-
Apache Avro Maven Plugin para projetos Maven
Estamos usando a versão 1.8.2 para este tutorial.
No entanto, é sempre aconselhável encontrar a versão mais recente emMaven Central:
org.apache.avro
avro-compiler
1.8.2
org.apache.avro
avro-maven-plugin
1.8.2
Depois de adicionar as dependências do maven, as próximas etapas serão:
-
Criação de esquema
-
Lendo o esquema em nosso programa
-
Serializando nossos dados usando o Avro
-
Por fim, desserialize os dados
6. Criação de esquema
A Avro descreve seu esquema usando um formato JSON. Existem principalmente quatro atributos para um determinado esquema do Avro:
-
Type- que descreve o tipo de esquema, seja seu tipo complexo ou valor primitivo
-
Namespace- que descreve o namespace ao qual o determinado esquema pertence
-
Name - o nome do Esquema
-
Fields- que informa sobre os campos associados a um determinado esquema. Fields can be of primitive as well as complex type.
Uma maneira de criar o esquema é escrever a representação JSON, como vimos nas seções anteriores.
Também podemos criar um esquema usandoSchemaBuilder, que é inegavelmente uma maneira melhor e eficiente de criá-lo.
6.1. UtilidadeSchemaBuilder
A classeorg.apache.avro.SchemaBuilder é útil para criar o Schema.
Em primeiro lugar, vamos criar o esquema paraClientIdentifier:
Schema clientIdentifier = SchemaBuilder.record("ClientIdentifier")
.namespace("com.example.avro")
.fields().requiredString("hostName").requiredString("ipAddress")
.endRecord();
Agora, vamos usar isso para criar um esquemaavroHttpRequest:
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();
É importante notar aqui que atribuímosclientIdentifier como o tipo para o campoclientIdentifier. Nesse caso,clientIdentifier usado para definir o tipo é o mesmo esquema que criamos antes.
Mais tarde, podemos aplicar o métodotoString para obter a estruturaJSON deSchema.
Schema files are saved using the .avsc extension. Vamos salvar nosso esquema gerado no arquivo“src/main/resources/avroHttpRequest-schema.avsc”.
7. Lendo o esquema
Ler um esquema é mais ou menos cerca decreating Avro classes for the given schema. Depois que as classes Avro são criadas, podemos usá-las para serializar e desserializar objetos.
Existem duas maneiras de criar classes Avro:
-
Gerando classes Avro programaticamente: as classes podem ser geradas usandoSchemaCompiler. Existem algumas APIs que podemos usar para gerar classes Java. Podemos encontrar o código para as classes de geração no GitHub.
-
Usando Maven para gerar classes
Nós temos um plugin maven que faz o trabalho bem. Precisamos incluir o plugin e executarmvn clean install.
Vamos adicionar o plugin ao nosso arquivopom.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. Serialização e desserialização com Avro
Quando terminarmos de gerar o esquema, vamos continuar explorando a parte de serialização.
Existem dois formatos de serialização de dados suportados pelo Avro: formato JSON e formato binário.
Primeiro, vamos nos concentrar no formato JSON e, em seguida, vamos discutir o formato Binário.
Antes de prosseguir, devemos passar por algumas interfaces principais. Podemos usar as interfaces e classes abaixo para serialização:
DatumWriter<T>: Devemos usar isso para escrever dados em um determinado esquema. Estaremos usando a implementaçãoSpecificDatumWriter em nosso exemplo, no entanto,DatumWriter tem outras implementações também. Outras implementações sãoGenericDatumWriter, Json.Writer, ProtobufDatumWriter, ReflectDatumWriter, ThriftDatumWriter.
Encoder: O codificador é usado ou definindo o formato conforme mencionado anteriormente. EncoderFactory fornece dois tipos de codificadores, codificador binário e codificador JSON.
DatumReader<D>: Interface única para desserialização. Novamente, ele tem várias implementações, mas usaremosSpecificDatumReader em nosso exemplo. Outras implementações são-GenericDatumReader, Json.ObjectReader, Json.Reader, ProtobufDatumReader, ReflectDatumReader, ThriftDatumReader.
Decoder: O decodificador é usado durante a desserialização dos dados. Decoderfactory fornece dois tipos de decodificadores: decodificador binário e decodificador JSON.
A seguir, vamos ver como a serialização e a desserialização acontecem no Avro.
8.1. Serialização
Vamos pegar o exemplo da classeAvroHttpRequest e tentar serializá-la usando Avro.
Em primeiro lugar, vamos serializá-lo no formato 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;
}
Vamos dar uma olhada em um caso de teste para este método:
@Test
public void whenSerialized_UsingJSONEncoder_ObjectGetsSerialized(){
byte[] data = serealizer.serealizeAvroHttpRequestJSON(request);
assertTrue(Objects.nonNull(data));
assertTrue(data.length > 0);
}
Aqui, usamos o métodojsonEncoder e passamos o esquema para ele.
Se quisermos usar um codificador binário, precisamos substituir o métodojsonEncoder() porbinaryEncoder():
Encoder jsonEncoder = EncoderFactory.get().binaryEncoder(stream,null);
8.2. Desserialização
Para fazer isso, usaremos as interfacesDatumReader eDecoder mencionadas acima.
Como usamosEncoderFactory para obter umEncoder,, usaremosDecoderFactory para obter um objetoDecoder.
Vamos desserializar os dados usando o formato 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());
}
}
E vamos ver o caso de teste:
@Test
public void whenDeserializeUsingJSONDecoder_thenActualAndExpectedObjectsAreEqual(){
byte[] data = serealizer.serealizeAvroHttpRequestJSON(request);
AvroHttpRequest actualRequest = deSerealizer
.deSerealizeAvroHttpRequestJSON(data);
assertEquals(actualRequest,request);
assertTrue(actualRequest.getRequestTime()
.equals(request.getRequestTime()));
}
Da mesma forma, podemos usar um decodificador binário:
Decoder decoder = DecoderFactory.get().binaryDecoder(data, null);
9. Conclusão
O Apache Avro é especialmente útil ao lidar com big data. Ele oferece serialização de dados no formato binário e JSON, que pode ser usado conforme o caso de uso.
O processo de serialização do Avro é mais rápido e também economiza espaço. A Avro não mantém as informações do tipo de campo em cada campo; em vez disso, ele cria metadados em um esquema.
Por último, mas não menos importante, o Avro tem uma ótima ligação com uma ampla variedade de linguagens de programação, o que lhe dá uma vantagem.
Como sempre, o código pode ser encontradoover on GitHub.