web-dev-qa-db-fra.com

Intégration de la diffusion structurée Spark au registre de schémas Confluent

J'utilise une source Kafka dans Spark Structured Streaming pour recevoir des enregistrements Avro codés Confluent. J'ai l'intention d'utiliser le registre de schéma Confluent, mais l'intégration avec le streaming structuré par étincelles semble impossible. 

J'ai vu cette question, mais je n'ai pas réussi à la faire fonctionner avec le registre de schéma Confluent. Lire des messages Avro de Kafka avec Spark 2.0.2 (streaming structuré)

8
Souhaib Guitouni

Il m'a fallu quelques mois pour lire le code source et tester les choses. En un mot, Spark ne peut gérer que la sérialisation Binary et String. Vous devez désérialiser les données manuellement. Dans spark, créez l'objet de service de repos confluent pour obtenir le schéma. Convertissez la chaîne de schéma dans l'objet de réponse en un schéma Avro à l'aide de l'analyseur Avro. Ensuite, lisez le sujet Kafka comme d'habitude. Puis mappez sur la colonne "valeur" typée binaire avec le KafkaAvroDeSerializer Confluent. Je suggère fortement d'entrer dans le code source de ces classes, car il se passe beaucoup de choses ici. Par souci de concision, je laisserai de côté de nombreux détails.

//Used Confluent version 3.2.2 to write this. 
import io.confluent.kafka.schemaregistry.client.rest.RestService
import io.confluent.kafka.serializers.KafkaAvroDeserializer
import org.Apache.avro.Schema

case class DeserializedFromKafkaRecord(key: String, value: String)

val schemaRegistryURL = "http://127.0.0.1:8081"

val topicName = "Schema-Registry-Example-topic1"
val subjectValueName = topicName + "-value"

//create RestService object
val restService = new RestService(schemaRegistryURL)

//.getLatestVersion returns io.confluent.kafka.schemaregistry.client.rest.entities.Schema object.
val valueRestResponseSchema = restService.getLatestVersion(subjectValueName)

//Use Avro parsing classes to get Avro Schema
val parser = new Schema.Parser
val topicValueAvroSchema: Schema = parser.parse(valueRestResponseSchema.getSchema)

//key schema is typically just string but you can do the same process for the key as the value
val keySchemaString = "\"string\""
val keySchema = parser.parse(keySchemaString)

//Create a map with the Schema registry url.
//This is the only Required configuration for Confluent's KafkaAvroDeserializer.
val props = Map("schema.registry.url" -> schemaRegistryURL)

//Declare SerDe vars before using Spark structured streaming map. Avoids non serializable class exception.
var keyDeserializer: KafkaAvroDeserializer = null
var valueDeserializer: KafkaAvroDeserializer = null

//Create structured streaming DF to read from the topic.
val rawTopicMessageDF = sql.readStream
  .format("kafka")
  .option("kafka.bootstrap.servers", "127.0.0.1:9092")
  .option("subscribe", topicName)
  .option("startingOffsets", "earliest")
  .option("maxOffsetsPerTrigger", 20)  //remove for prod
  .load()

//instantiate the SerDe classes if not already, then deserialize!
val deserializedTopicMessageDS = rawTopicMessageDF.map{
  row =>
    if (keyDeserializer == null) {
      keyDeserializer = new KafkaAvroDeserializer
      keyDeserializer.configure(props.asJava, true)  //isKey = true
    }
    if (valueDeserializer == null) {
      valueDeserializer = new KafkaAvroDeserializer
      valueDeserializer.configure(props.asJava, false) //isKey = false
    }

    //Pass the Avro schema.
    val deserializedKeyString = keyDeserializer.deserialize(topicName, row.key, keySchema).toString //topic name is actually unused in the source code, just required by the signature. Weird right?
    val deserializedValueJsonString = valueDeserializer.deserialize(topicName, row.value, topicValueAvroSchema).toString

    DeserializedFromKafkaRecord(DeserializedKeyString, DeserializedValueJsonString)
}

val deserializedDSOutputStream = deserializedTopicMessageDS.writeStream
    .outputMode("append")
    .format("console")
    .option("truncate", false)
    .start()
13
tstites

Cette bibliothèque fera le travail pour vous. Il se connecte à Kafka Confluent et au registre de schémas via Spark Structured Stream.

Pour Confluent, il gère l'identificateur de schéma envoyé avec la charge utile.

Dans le README, vous trouverez un extrait de code expliquant comment le faire.

DIVULGATION: Je travaille pour ABSA et j'ai développé cette bibliothèque.

2

Découvrez ce projet - https://github.com/hortonworks-spark/spark-schema-registry

Cela vous permet d'intégrer le registre Schema de Hortonwork ( https://github.com/hortonworks/registry ) à Spark. Il est également possible de l'insérer dans le registre Schéma Confluent (car le registre Schéma Hortonworks est compatible avec celui de Confluent), mais vous devrez l'explorer davantage.

0
arunmahadevan