如何在火花流中引发异常

时间:2017-12-18 17:05:54

标签: java apache-spark spark-streaming

我们有一个火花流程序,它从kafka中提取消息并使用forEachPartiton转换处理每条消息。

如果处理函数中存在特定错误,我们希望将异常抛回并暂停程序。似乎没有发生同样的事情。下面是我们试图执行的代码。

JavaInputDStream<KafkaDTO> stream = KafkaUtils.createDirectStream( ...);

stream.foreachRDD(new Function<JavaRDD<KafkaDTO>, Void>() {

    public Void call(JavaRDD<KafkaDTO> rdd) throws PropertiesLoadException, Exception {    
         rdd.foreachPartition(new VoidFunction<Iterator<KafkaDTO>>() {

             @Override
             public void call(Iterator<KafkaDTO> itr) throws PropertiesLoadException, Exception {
                 while (itr.hasNext()) {
                     KafkaDTO dto = itr.next();
                     try{
                       //process the message here.
                     } catch (PropertiesLoadException e) {
                         // throw Exception if property file is not found
                         throw new PropertiesLoadException(" PropertiesLoadException: "+e.getMessage());
                     } catch (Exception e) {
                         throw new Exception(" Exception : "+e.getMessage());
                     }
                 }
             }
         });
     }
 }

在上面的代码中,即使我们抛出PropertiesLoadException,程序也不会停止并继续流式传输。我们在Spark配置中设置的最大重试次数仅为4.流式程序即使在4次失败后也会继续。如何抛出异常来停止程序?

1 个答案:

答案 0 :(得分:1)

我不确定这是否是最好的方法,但我们用try和catch包围了主要批处理,当我得到异常时,我只是调用close上下文。此外,你需要确保关闭停止(假)。

示例代码:

try {
    process(dataframe);
} catch (Exception e) {
    logger.error("Failed on write - will stop spark context immediately!!" + e.getMessage());
    closeContext(jssc);
    if (e instanceof InterruptedException) {
        Thread.currentThread().interrupt();
    }
    throw e;
}

关闭功能:

private void closeContext(JavaStreamingContext jssc) {
    logger.warn("stopping the context");
    jssc.stop(false, jssc.sparkContext().getConf().getBoolean("spark.streaming.stopGracefullyOnShutdown", false));
    logger.error("Context was stopped");
}

在配置中

spark.streaming.stopGracefullyOnShutdown false

我认为使用您的代码应该如下所示:

JavaStreamingContext jssc = new JavaStreamingContext(sparkConf, streamBatch);
JavaInputDStream<KafkaDTO> stream = KafkaUtils.createDirectStream( jssc, ...);

    stream.foreachRDD(new Function<JavaRDD<KafkaDTO>, Void>() {

        public Void call(JavaRDD<KafkaDTO> rdd) throws PropertiesLoadException, Exception {

            try {

                rdd.foreachPartition(new VoidFunction<Iterator<KafkaDTO>>() {

                    @Override
                    public void call(Iterator<KafkaDTO> itr) throws PropertiesLoadException, Exception {
                        while (itr.hasNext()) {
                            KafkaDTO dto = itr.next();
                            try {
                                //process the message here.
                            } catch (PropertiesLoadException e) {
                                // throw Exception if property file is not found
                                throw new PropertiesLoadException(" PropertiesLoadException: " + e.getMessage());
                            } catch (Exception e) {
                                throw new Exception(" Exception : " + e.getMessage());
                            }
                        }
                    }
                });

            } catch (Exception e){
                logger.error("Failed on write - will stop spark context immediately!!" + e.getMessage());
                closeContext(jssc);
                if (e instanceof InterruptedException) {
                    Thread.currentThread().interrupt();
                }
                throw e;
            }

        }
    }

另外请注意我的流正在使用spark 2.1 Standalone(非yarn / mesos)客户端模式。另外,我使用ZK优雅地实现了自我停止。