java.util.ConcurrentModificationException:KafkaConsumer对多线程访问不安全

时间:2018-01-15 15:13:11

标签: multithreading scala apache-spark apache-kafka spark-streaming

我有一个Scala Spark Streaming个应用程序,它接收来自3个不同Kafka producers的同一主题的数据。

Spark流媒体应用程序位于主机0.0.0.179的计算机上,Kafka服务器位于主机0.0.0.178的计算机上,Kafka producers位于计算机上,0.0.0.180,{{ 1}},0.0.0.181

当我尝试运行0.0.0.182应用程序时遇到错误

  

线程“main”中的异常org.apache.spark.SparkException:Job   由于阶段失败而中止:阶段19.0中的任务0失败1次,   最近的失败:阶段19.0中失去的任务0.0(TID 19,localhost):   java.util.ConcurrentModificationException:KafkaConsumer不安全   用于多线程访问   org.apache.kafka.clients.consumer.KafkaConsumer.acquire(KafkaConsumer.java:1625)   在   org.apache.kafka.clients.consumer.KafkaConsumer.seek(KafkaConsumer.java:1198)   在   org.apache.spark.streaming.kafka010.CachedKafkaConsumer.seek(CachedKafkaConsumer.scala:95)   在   org.apache.spark.streaming.kafka010.CachedKafkaConsumer.get(CachedKafkaConsumer.scala:69)   在   org.apache.spark.streaming.kafka010.KafkaRDD $ KafkaRDDIterator.next(KafkaRDD.scala:228)   在   org.apache.spark.streaming.kafka010.KafkaRDD $ KafkaRDDIterator.next(KafkaRDD.scala:194)   在scala.collection.Iterator $$ anon $ 11.next(Iterator.scala:409)at   scala.collection.Iterator $$ anon $ 11.next(Iterator.scala:409)at   org.apache.spark.rdd.PairRDDFunctions $$ anonfun $ saveAsHadoopDataset $ 1 $$ anonfun $ 13 $$ anonfun $ $应用$ 7.apply MCV $ SP(PairRDDFunctions.scala:1204)   在   org.apache.spark.rdd.PairRDDFunctions $$ anonfun $ saveAsHadoopDataset $ 1 $$ anonfun $ 13 $$ anonfun $ $申请7.apply(PairRDDFunctions.scala:1203)   在   org.apache.spark.rdd.PairRDDFunctions $$ anonfun $ saveAsHadoopDataset $ 1 $$ anonfun $ 13 $$ anonfun $ $申请7.apply(PairRDDFunctions.scala:1203)   在   org.apache.spark.util.Utils $ .tryWithSafeFinallyAndFailureCallbacks(Utils.scala:1325)   在   org.apache.spark.rdd.PairRDDFunctions $$ anonfun $ saveAsHadoopDataset $ 1 $$ anonfun $ 13.apply(PairRDDFunctions.scala:1211)   在   org.apache.spark.rdd.PairRDDFunctions $$ anonfun $ saveAsHadoopDataset $ 1 $$ anonfun $ 13.apply(PairRDDFunctions.scala:1190)   在org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:70)   在org.apache.spark.scheduler.Task.run(Task.scala:85)at   org.apache.spark.executor.Executor $ TaskRunner.run(Executor.scala:274)   在   java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)   在   java.util.concurrent.ThreadPoolExecutor中的$ Worker.run(ThreadPoolExecutor.java:617)   在java.lang.Thread.run(Thread.java:748)

现在我阅读了数千个不同的帖子,但似乎没有人能够在这个问题上找到解决方案。

如何在我的应用程序中处理此问题?我是否必须修改Kakfa上的一些参数(当Spark Streaming参数设置为1时)?

以下是我的申请代码:

num.partition

谢谢

2 个答案:

答案 0 :(得分:3)

你的问题在这里:

s1.print()
s1.saveAsTextFiles("results/", "")

由于Spark创建了一个流图,并且您在此处定义了两个流:

Read from Kafka -> Print to console
Read from Kafka -> Save to text file

Spark将尝试同时运行这两个图,因为它们彼此独立。由于Kafka使用缓存的消费者方法,因此它有效地尝试将两个流执行使用相同的消费者。

您可以做的是在运行两个查询之前缓存DStream

val dataFromKafka = KafkaUtils.createDirectStream[String, String](ssc, PreferConsistent, Subscribe[String, String](topics1, kafkaParams)).map(/* stuff */)

val cachedStream = dataFromKafka.cache()
cachedStream.print()
cachedStream.saveAsTextFiles("results/", "")

答案 1 :(得分:0)

使用缓存对我有用。就我而言,在JavaPairDstream上进行打印,转换然后进行打印,这给了我这个错误。 我在第一次打印之前就使用了缓存,它对我有用。

s1.print()
s1.saveAsTextFiles("results/", "")

下面的代码将起作用,我使用了类似的代码。

s1.cache();
s1.print();
s1.saveAsTextFiles("results/", "");