web-dev-qa-db-fra.com

KafkaAvroSerializer pour sérialiser Avro sans schema.registry.url

Je suis un noob pour Kafka et Avro. J'ai donc essayé de faire fonctionner le producteur/consommateur. Jusqu'à présent, j'ai pu produire et consommer des octets et des chaînes simples, en utilisant ce qui suit : Configuration pour le producteur:

    Properties props = new Properties();
    props.put("bootstrap.servers", "localhost:9092");
    props.put("key.serializer", "org.Apache.kafka.common.serialization.StringSerializer");
    props.put("value.serializer", "org.Apache.kafka.common.serialization.ByteArraySerializer");

    Schema.Parser parser = new Schema.Parser();
    Schema schema = parser.parse(USER_SCHEMA);
    Injection<GenericRecord, byte[]> recordInjection = GenericAvroCodecs.toBinary(schema);

    KafkaProducer<String, byte[]> producer = new KafkaProducer<>(props);

    for (int i = 0; i < 1000; i++) {
        GenericData.Record avroRecord = new GenericData.Record(schema);
        avroRecord.put("str1", "Str 1-" + i);
        avroRecord.put("str2", "Str 2-" + i);
        avroRecord.put("int1", i);

        byte[] bytes = recordInjection.apply(avroRecord);

        ProducerRecord<String, byte[]> record = new ProducerRecord<>("mytopic", bytes);
        producer.send(record);
        Thread.sleep(250);
    }
    producer.close();
}

Maintenant, tout va bien, le problème survient lorsque j'essaie de sérialiser un POJO. J'ai donc pu obtenir l'AvroSchema du POJO en utilisant l'utilitaire fourni avec Avro. Codé en dur le schéma, puis essayé de créer un enregistrement générique à envoyer via le KafkaProducer, le producteur est maintenant configuré comme:

    Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", "org.Apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.Apache.kafka.common.serialization.KafkaAvroSerializer");

Schema.Parser parser = new Schema.Parser();
Schema schema = parser.parse(USER_SCHEMA); // this is the Generated AvroSchema
KafkaProducer<String, byte[]> producer = new KafkaProducer<>(props);

c'est là que réside le problème: au moment où j'utilise KafkaAvroSerializer, le producteur ne revient pas à cause de: paramètre obligatoire manquant: schema.registry.url

J'ai lu pourquoi cela est nécessaire, afin que mon consommateur puisse déchiffrer tout ce que le producteur m'envoie. Mais le schéma n'est-il pas déjà intégré dans l'AvroMessage? Ce serait vraiment bien si quelqu'un pouvait partager un exemple de travail d'utilisation de KafkaProducer avec KafkaAvroSerializer sans avoir à spécifier schema.registry.url

apprécierait également vraiment toutes les informations/ressources sur l'utilité du registre de schéma.

merci!

12
scissorHands

Remarque d'abord: KafkaAvroSerializer n'est pas fourni dans Vanilla Apache kafka - il est fourni par Confluent Platform. ( https://www.confluent.io/ =), dans le cadre de ses composants open source ( http://docs.confluent.io/current/platform.html#confluent-schema-registry )

Réponse rapide: non, si vous utilisez KafkaAvroSerializer, vous aurez besoin d'un registre de schéma. Voir quelques exemples ici: http://docs.confluent.io/current/schema-registry/docs/serializer-formatter.html

L'idée de base avec le registre de schéma est que chaque rubrique fera référence à un schéma avro (c'est-à-dire que vous ne pourrez envoyer des données cohérentes les unes que les autres. Mais un schéma peut avoir plusieurs versions, vous devez donc toujours identifier le schéma pour chaque record)

Nous ne voulons pas écrire le schéma pour everydata comme vous l'impliquez - souvent, le schéma est plus grand que vos données! Ce serait une perte de temps à les analyser à chaque lecture et une perte de ressources (réseau, disque, cpu)

Au lieu de cela, une instance de registre de schéma fera une liaison avro schema <-> int schemaId et le sérialiseur écrira alors uniquement cet identifiant avant les données, après l'avoir récupéré du registre (et l'avoir mis en cache pour une utilisation ultérieure).

Donc, à l'intérieur de kafka, votre dossier sera [<id> <bytesavro>] (et octet magique pour des raisons techniques), ce qui représente une surcharge de seulement 5 octets (à comparer à la taille de votre schéma) . Vous pouvez trouver bien plus dans la doc confluente

Si vous avez vraiment une utilisation où vous voulez écrire le schéma pour chaque enregistrement, vous aurez besoin d'un autre sérialiseur (je pense que l'écriture du vôtre, mais ce sera facile, il suffit de réutiliser https://github.com/ confluentinc/schema-registry/blob/master/avro-serializer/src/main/Java/io/confluent/kafka/serializers/AbstractKafkaAvroSerializer.Java et supprimez la partie de registre de schéma pour la remplacer par le schéma, même pour la lecture ). Mais si vous utilisez avro, je découragerais vraiment cela - un jour plus tard, vous devrez implémenter quelque chose comme le registre avro pour gérer la gestion des versions

19
Treziac

Bien que la réponse vérifiée soit correcte, il convient également de mentionner que l'enregistrement du schéma peut être désactivé.

Réglez simplement auto.register.schemas à false.

0
Fritz Duchardt

Vous pouvez toujours créer vos classes de valeurs pour implémenter Serialiser<T>, Deserialiser<T> (et Serde<T> pour Kafka Streams) manuellement. Java sont généralement générées à partir de fichiers Avro, donc l'édition directement n'est pas une bonne idée, mais l'habillage est peut-être verbeux mais possible.

Une autre façon consiste à régler les modèles de générateur Arvo qui sont utilisés pour Java et générer automatiquement l'implémentation de toutes ces interfaces. Les plugins Avro maven et gradle prennent en charge les modèles personnalisés, il devrait donc être facile à configurer .

J'ai créé https://github.com/artemyarulin/avro-kafka-deserializable qui a changé les fichiers modèles et un outil CLI simple que vous pouvez utiliser pour la génération de fichiers

0
Artem Yarulin