J'utilise le code ci-dessous pour lire le sujet de Kafka et traiter les données.
JavaDStream<Row> transformedMessages = messages.flatMap(record -> processData(record))
.transform(new Function<JavaRDD<Row>, JavaRDD<Row>>() {
//JavaRDD<Row> records = ss.emptyDataFrame().toJavaRDD();
StructType schema = DataTypes.createStructType(fields);
public JavaRDD<Row> call(JavaRDD<Row> rdd) throws Exception {
records = rdd.union(records);
return rdd;
}
});
transformedMessages.foreachRDD(record -> {
//System.out.println("Aman" +record.count());
StructType schema = DataTypes.createStructType(fields);
Dataset ds = ss.createDataFrame(records, schema);
ds.createOrReplaceTempView("trades");
System.out.println(ds.count());
ds.show();
});
En exécutant le code, je reçois une exception ci-dessous:
Caused by: Java.util.ConcurrentModificationException: KafkaConsumer is not safe for multi-threaded access
at org.Apache.kafka.clients.consumer.KafkaConsumer.acquire(KafkaConsumer.Java:1624)
at org.Apache.kafka.clients.consumer.KafkaConsumer.seek(KafkaConsumer.Java:1197)
at org.Apache.spark.streaming.kafka010.CachedKafkaConsumer.seek(CachedKafkaConsumer.scala:95)
at org.Apache.spark.streaming.kafka010.CachedKafkaConsumer.get(CachedKafkaConsumer.scala:69)
at org.Apache.spark.streaming.kafka010.KafkaRDD$KafkaRDDIterator.next(KafkaRDD.scala:228)
at org.Apache.spark.streaming.kafka010.KafkaRDD$KafkaRDDIterator.next(KafkaRDD.scala:194)
at scala.collection.Iterator$$anon$12.nextCur(Iterator.scala:434)
at scala.collection.Iterator$$anon$12.hasNext(Iterator.scala:440)
at scala.collection.Iterator$$anon$11.hasNext(Iterator.scala:408)
at scala.collection.Iterator$$anon$11.hasNext(Iterator.scala:408)
at org.Apache.spark.sql.catalyst.expressions.GeneratedClass$GeneratedIterator.agg_doAggregateWithoutKey$(Unknown Source)
at org.Apache.spark.sql.catalyst.expressions.GeneratedClass$GeneratedIterator.processNext(Unknown Source)
at org.Apache.spark.sql.execution.BufferedRowIterator.hasNext(BufferedRowIterator.Java:43)
at org.Apache.spark.sql.execution.WholeStageCodegenExec$$anonfun$8$$anon$1.hasNext(WholeStageCodegenExec.scala:377)
at scala.collection.Iterator$$anon$11.hasNext(Iterator.scala:408)
at org.Apache.spark.shuffle.sort.BypassMergeSortShuffleWriter.write(BypassMergeSortShuffleWriter.Java:126)
at org.Apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:96)
at org.Apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:53)
at org.Apache.spark.scheduler.Task.run(Task.scala:99)
at org.Apache.spark.executor.Executor$TaskRunner.run(Executor.scala:322)
Le fait que je n’ai qu’un seul DStream, je ne sais pas trop pourquoi je reçois cette exception… .. Je lis à partir de 3 partitions d’un sujet Kafka. Je suppose que le "createDirectStream" va créer 3 consommateurs pour lire les données.
Vous trouverez ci-dessous le code correspondant à la méthode KafkaConsumer:
private void acquire() {
this.ensureNotClosed();
long threadId = Thread.currentThread().getId();
if(threadId != this.currentThread.get() && !this.currentThread.compareAndSet(-1L, threadId)) {
throw new ConcurrentModificationException("KafkaConsumer is not safe for multi-threaded access");
} else {
this.refcount.incrementAndGet();
}
}
Spark 2.2.0 propose une solution de contournement sans cache . Utilisez simplement spark.streaming.kafka.consumer.cache.enabled à false
. Consultez la demande pull
Dans ce morceau de code, vous effectuez deux actions sur RDD
transformedMessages.foreachRDD(record -> {
//System.out.println("Aman" +record.count());
StructType schema =
DataTypes.createStructType(fields);
Dataset ds = ss.createDataFrame(records, schema);
ds.createOrReplaceTempView("trades");
System.out.println(ds.count());
ds.show();
});
Deux consommateurs de Consumer Group ont essayé de lire la partition de sujet Kafka, mais Kafka permet à un seul consommateur d'un groupe de consommateurs de lire la partition de sujet Kafka. La solution à ce problème est la suivante: mettre en cache le RDD
transformedMessages.foreachRDD(record -> {
//System.out.println("Aman" +record.count());
StructType schema =
DataTypes.createStructType(fields);
Dataset ds = ss.createDataFrame(records, schema);
ds.cache()
System.out.println(ds.count());
ds.show();
});
Il s'agit d'un problème similaire de Java.util.ConcurrentModificationException: KafkaConsumer n'est pas sécurisé pour les accès multithreads , plusieurs threads s'exécutant avec le même consommateur et Kafka ne prend pas en charge le multithreading. Assurez-vous également que vous n'utilisez pas spark.speculation = true car cela entraînera l'erreur mentionnée ci-dessus.
Comme décrit dans ce rapport de bogue: https://issues.Apache.org/jira/browse/SPARK-19185 , il s’agit d’un problème connu de Spark/Kafka.
Dans mon cas, je vais éviter d'utiliser window et d'utiliser le partitionnement en combinaison avec batchInterval et blockInterval, comme décrit ici: https://spark.Apache.org/docs/latest/streaming-programming-guide.html# niveau de parallélisme dans la réception de données