Параллельное исключение для KafkaConsumer не является безопасным для многопоточного доступа

Мы вызываем работу SparkSQL из потоковой передачи Spark. Мы получаем параллельное исключение, и потребитель Kafka закрывается из-за ошибки. Вот код и детали исключения:

Потребительский код Кафки

// Start reading messages from Kafka and get DStream
        final JavaInputDStream<ConsumerRecord<String, byte[]>> consumerStream = KafkaUtils.createDirectStream(
                getJavaStreamingContext(), LocationStrategies.PreferConsistent(),
                ConsumerStrategies.<String, byte[]>Subscribe(SparkServiceConfParams.AIR.CONSUME_TOPICS,
                        sparkServiceConf.getKafkaConsumeParams()));

        ThreadContext.put(Constants.CommonLiterals.LOGGER_UID_VAR, CommonUtils.loggerUniqueId());
    // Decode each binary message and generate JSON array
    JavaDStream<String> decodedStream = messagesStream.map(new Function<byte[], String>() {}

..

    // publish generated json gzip to kafka 
    decodedStream.foreachRDD(new VoidFunction<JavaRDD<String>>() {
        private static final long serialVersionUID = 1L;

        @Override
        public void call(JavaRDD<String> jsonRdd4DF) throws Exception {
            //Dataset<Row> json = sparkSession.read().json(jsonRdd4DF);
            if(!jsonRdd4DF.isEmpty()) {
                //JavaRDD<String> jsonRddDF = getJavaSparkContext().parallelize(jsonRdd4DF.collect());
                Dataset<Row> json = sparkSession.read().json(jsonRdd4DF);   

                SparkAIRMainJsonProcessor airMainJsonProcessor = new SparkAIRMainJsonProcessor();

                    AIRDataSetBean processAIRData = airMainJsonProcessor.processAIRData(json, sparkSession);

Сведения об ошибке

    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.util.ConcurrentModificationException: KafkaConsumer is not safe for multi-threaded access

Наконец-то потребитель Кафки закрылся:

org.apache.spark.sql.execution.datasources.InsertIntoHadoopFsRelationCommand$$anonfun$run$1$$anonfun$apply$mcV$sp$1.apply(InsertIntoHadoopFsRelationCommand.scala:143)
    at org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:70)
    at org.apache.spark.scheduler.Task.run(Task.scala:86)
    at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:274)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: 

This consumer has already been closed.

1 ответ

Решение

Эта проблема решается с помощью параметра "Кэш" или "Сохранять" потоковой передачи Spark. В этом сценарии с использованием кэша RDD больше не считывается с Kafka, и проблема устранена. Это позволяет одновременное использование потока. Но, пожалуйста, используйте мудро кеширование. Вот код:

JavaDStream<ConsumerRecord<String, byte[]>> cache = consumerStream.cache();
Другие вопросы по тегам