Guide pour Apache Avro

Guide d'Apache Avro

1. Vue d'ensemble

La sérialisation des données est une technique de conversion des données en format binaire ou texte. Il existe plusieurs systèmes disponibles à cet effet. Apache Avro est l'un de ces systèmes de sérialisation de données.

Avro is a language independent, schema-based data serialization library. Il utilise un schéma pour effectuer la sérialisation et la désérialisation. De plus, Avro utilise un format JSON pour spécifier la structure de données qui la rend plus puissante.

Dans ce didacticiel, nous explorerons plus en détail la configuration d'Avro, l'API Java pour effectuer la sérialisation et une comparaison d'Avro avec d'autres systèmes de sérialisation de données.

Nous nous concentrerons principalement sur la création de schémas qui est la base de l'ensemble du système.

2. Apache Avro

Avro est une bibliothèque de sérialisation indépendante de la langue. Pour ce faire, Avro utilise un schéma qui est l’un des composants principaux. Ilstores the schema in a file for further data processing.

Avro est la meilleure solution pour le traitement Big Data. Il est très populaire dans le monde Hadoop et Kafka pour son traitement plus rapide.

Avro crée un fichier de données dans lequel il conserve les données avec le schéma dans sa section de métadonnées. Surtout, il fournit une structure de données riche qui le rend plus populaire que d’autres solutions similaires.

Pour utiliser Avro pour la sérialisation, nous devons suivre les étapes mentionnées ci-dessous.

3. Déclaration du problème

Commençons par définir une classe appeléeAvroHttRequest que nous utiliserons pour nos exemples. La classe contient des attributs de type primitif et complexe:

class AvroHttpRequest {

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

Ici,requestTime est une valeur primitive. ClientIdentifier est une autre classe qui représente un type complexe. Nous avons aussiemployeeName qui est encore un type complexe. Active est une énumération pour décrire si la liste d'employés donnée est active ou non.

Notre objectif est de sérialiser et désérialiser la classeAvroHttRequest à l'aide d'Apache Avro.

4. Types de données Avro

Avant de poursuivre, examinons les types de données pris en charge par Avro.

Avro supporte deux types de données:

  • Type primitif: Avro supporte tous les types primitifs. Nous utilisons un nom de type primitif pour définir le type d'un champ donné. Par exemple, une valeur qui contient unString doit être déclarée comme \ {"type": "string"} dans Schema

  • Type complexe: Avro prend en charge six types de types complexes: enregistrements, énumérations, tableaux, cartes, unions et fixes.

Par exemple, dans notre énoncé de problème,ClientIdentifier est un enregistrement.

Dans ce cas, le schéma pourClientIdentifier devrait ressembler à:

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

5. Utiliser Avro

Pour commencer, ajoutons les dépendances Maven dont nous aurons besoin dans notre fichierpom.xml.

Nous devrions inclure les dépendances suivantes:

  • Apache Avro - composants de base

  • Compilateur - Compilateurs Apache Avro pour Avro IDL et Java APIT spécifiques à Avro

  • Outils - comprenant les outils et utilitaires de ligne de commande Apache Avro

  • Apache Avro Maven Plugin pour les projets Maven

Nous utilisons la version 1.8.2 pour ce didacticiel.

Cependant, il est toujours conseillé de trouver la dernière version surMaven Central:


    org.apache.avro
    avro-compiler
    1.8.2


    org.apache.avro
    avro-maven-plugin
    1.8.2

Après avoir ajouté les dépendances Maven, les prochaines étapes seront les suivantes:

  • Création de schéma

  • Lire le schéma dans notre programme

  • Sérialiser nos données en utilisant Avro

  • Enfin, désérialiser les données

6. Création de schéma

Avro décrit son schéma en utilisant un format JSON. Il y a principalement quatre attributs pour un schéma d'Avro donné:

  • Type- qui décrit le type de schéma que ce soit son type complexe ou sa valeur primitive

  • Namespace- qui décrit l'espace de noms auquel appartient le schéma donné

  • Name - le nom du schéma

  • Fields- qui renseigne sur les champs associés à un schéma donné. Fields can be of primitive as well as complex type.

Une façon de créer le schéma consiste à écrire la représentation JSON, comme nous l'avons vu dans les sections précédentes.

Nous pouvons également créer un schéma en utilisantSchemaBuilder, ce qui est indéniablement un moyen meilleur et efficace de le créer.

6.1. UtilitaireSchemaBuilder

La classeorg.apache.avro.SchemaBuilder est utile pour créer le schéma.

Tout d'abord, créons le schéma pourClientIdentifier:

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

Maintenant, utilisons ceci pour créer un schémaavroHttpRequest:

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();

Il est important de noter ici que nous avons attribuéclientIdentifier comme type pour le champclientIdentifier. Dans ce cas,clientIdentifier utilisé pour définir le type est le même schéma que nous avons créé auparavant.

Plus tard, nous pouvons appliquer la méthodetoString pour obtenir la structureJSON deSchema.

Schema files are saved using the .avsc extension. Sauvegardons notre schéma généré dans le fichier“src/main/resources/avroHttpRequest-schema.avsc”.

7. Lecture du schéma

La lecture d'un schéma est plus ou moins d'environcreating Avro classes for the given schema. Une fois que les classes Avro sont créées, nous pouvons les utiliser pour sérialiser et désérialiser des objets.

Il existe deux manières de créer des classes Avro:

  • Génération de classes Avro par programme: Les classes peuvent être générées en utilisantSchemaCompiler. Il y a quelques API que nous pouvons utiliser pour générer des classes Java. Nous pouvons trouver le code pour les classes de génération sur GitHub.

  • Utiliser Maven pour générer des classes

Nous avons un plugin Maven qui fait le travail bien. Nous devons inclure le plugin et exécutermvn clean install.

Ajoutons le plugin à notre fichierpom.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. Sérialisation et désérialisation avec Avro

Comme nous en avons terminé avec la génération du schéma, continuons à explorer la partie sérialisation.

Avro prend en charge deux formats de sérialisation des données: le format JSON et le format binaire.

Tout d'abord, nous nous concentrerons sur le format JSON, puis nous discuterons du format binaire.

Avant de poursuivre, nous devrions passer par quelques interfaces clés. Nous pouvons utiliser les interfaces et les classes ci-dessous pour la sérialisation:

DatumWriter<T>: Nous devrions l'utiliser pour écrire des données sur un schéma donné. Nous allons utiliser l'implémentationSpecificDatumWriter dans notre exemple, cependant,DatumWriter a également d'autres implémentations. Les autres implémentations sontGenericDatumWriter, Json.Writer, ProtobufDatumWriter, ReflectDatumWriter, ThriftDatumWriter.

Encoder: l'encodeur est utilisé ou définit le format comme mentionné précédemment. EncoderFactory fournit deux types d'encodeurs, l'encodeur binaire et l'encodeur JSON.

DatumReader<D>: Interface unique pour la désérialisation. Encore une fois, il a plusieurs implémentations, mais nous utiliseronsSpecificDatumReader dans notre exemple. Les autres implémentations sont-GenericDatumReader, Json.ObjectReader, Json.Reader, ProtobufDatumReader, ReflectDatumReader, ThriftDatumReader.

Decoder: Le décodeur est utilisé lors de la désérialisation des données. Decoderfactory fournit deux types de décodeurs: le décodeur binaire et le décodeur JSON.

Voyons ensuite comment la sérialisation et la désérialisation se produisent dans Avro.

8.1. La sérialisation

Nous allons prendre l'exemple de la classeAvroHttpRequest et essayer de la sérialiser à l'aide d'Avro.

Tout d'abord, sérialisons-le au format 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;
}

Jetons un coup d'œil à un cas de test pour cette méthode:

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

Ici, nous avons utilisé la méthodejsonEncoder et lui avons passé le schéma.

Si nous voulions utiliser un encodeur binaire, nous devons remplacer la méthodejsonEncoder() parbinaryEncoder():

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

8.2. Désérialisation

Pour ce faire, nous utiliserons les interfacesDatumReader etDecoder mentionnées ci-dessus.

Comme nous avons utiliséEncoderFactory pour obtenir unEncoder, de la même manière, nous utiliseronsDecoderFactory pour obtenir un objetDecoder.

Désérialisons les données au format 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());
    }
}

Et voyons le cas de test:

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

De même, nous pouvons utiliser un décodeur binaire:

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

9. Conclusion

Apache Avro est particulièrement utile pour traiter des données volumineuses. Il offre une sérialisation des données au format binaire et JSON qui peut être utilisé selon le cas d'utilisation.

Le processus de sérialisation d’Avro est plus rapide et peu encombrant. Avro ne conserve pas les informations de type de champ avec chaque champ; au lieu de cela, il crée des métadonnées dans un schéma.

Dernier point, mais non des moindres, Avro possède une excellente liaison avec un large éventail de langages de programmation, ce qui lui donne un avantage.

Comme toujours, le code peut être trouvéover on GitHub.