try catch块未捕获异常

时间:2019-02-19 11:26:33

标签: scala apache-spark exception-handling try-catch spark-streaming

我正在将DStream保存到Cassandra。卡桑德拉(Cassandra)中有一列,数据类型为map<text, text>。 Cassandra在Map中不支持null值,但流中可能出现空值。

如果情况出现问题,我已经添加了try catch,但是尽管如此,程序仍然停止了,并且我在日志中没有看到错误消息:

   try {
      cassandraStream.saveToCassandra("table", "keyspace")
    } catch {
      case e: Exception => log.error("Error in saving data in Cassandra" + e.getMessage, e)
    }

例外

Caused by: java.lang.NullPointerException: Map values cannot be null
    at com.datastax.driver.core.TypeCodec$AbstractMapCodec.serialize(TypeCodec.java:2026)
    at com.datastax.driver.core.TypeCodec$AbstractMapCodec.serialize(TypeCodec.java:1909)
    at com.datastax.driver.core.AbstractData.set(AbstractData.java:530)
    at com.datastax.driver.core.AbstractData.set(AbstractData.java:536)
    at com.datastax.driver.core.BoundStatement.set(BoundStatement.java:870)
    at com.datastax.spark.connector.writer.BoundStatementBuilder.com$datastax$spark$connector$writer$BoundStatementBuilder$$bindColumnUnset(BoundStatementBuilder.scala:73)
    at com.datastax.spark.connector.writer.BoundStatementBuilder$$anonfun$6.apply(BoundStatementBuilder.scala:84)
    at com.datastax.spark.connector.writer.BoundStatementBuilder$$anonfun$6.apply(BoundStatementBuilder.scala:84)
    at com.datastax.spark.connector.writer.BoundStatementBuilder$$anonfun$bind$1.apply$mcVI$sp(BoundStatementBuilder.scala:106)
    at scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:160)
    at com.datastax.spark.connector.writer.BoundStatementBuilder.bind(BoundStatementBuilder.scala:101)
    at com.datastax.spark.connector.writer.GroupingBatchBuilder.next(GroupingBatchBuilder.scala:106)
    at com.datastax.spark.connector.writer.GroupingBatchBuilder.next(GroupingBatchBuilder.scala:31)
    at scala.collection.Iterator$class.foreach(Iterator.scala:893)
    at com.datastax.spark.connector.writer.GroupingBatchBuilder.foreach(GroupingBatchBuilder.scala:31)
    at com.datastax.spark.connector.writer.TableWriter$$anonfun$writeInternal$1.apply(TableWriter.scala:233)
    at com.datastax.spark.connector.writer.TableWriter$$anonfun$writeInternal$1.apply(TableWriter.scala:210)
    at com.datastax.spark.connector.cql.CassandraConnector$$anonfun$withSessionDo$1.apply(CassandraConnector.scala:112)
    at com.datastax.spark.connector.cql.CassandraConnector$$anonfun$withSessionDo$1.apply(CassandraConnector.scala:111)
    at com.datastax.spark.connector.cql.CassandraConnector.closeResourceAfterUse(CassandraConnector.scala:145)
    at com.datastax.spark.connector.cql.CassandraConnector.withSessionDo(CassandraConnector.scala:111)
    at com.datastax.spark.connector.writer.TableWriter.writeInternal(TableWriter.scala:210)
    at com.datastax.spark.connector.writer.TableWriter.insert(TableWriter.scala:197)
    at com.datastax.spark.connector.writer.TableWriter.write(TableWriter.scala:183)
    at com.datastax.spark.connector.streaming.DStreamFunctions$$anonfun$saveToCassandra$1$$anonfun$apply$1.apply(DStreamFunctions.scala:54)
    at com.datastax.spark.connector.streaming.DStreamFunctions$$anonfun$saveToCassandra$1$$anonfun$apply$1.apply(DStreamFunctions.scala:54)
    at org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:87)
    at org.apache.spark.scheduler.Task.run(Task.scala:109)
    at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:345)
    ... 3 more

尽管有try / catch块,我想知道为什么程序会停止。为什么未捕获到异常?

2 个答案:

答案 0 :(得分:1)

要了解失败的根源,您必须承认,DStreamFunctions.saveToCassandra与总体上DStream的输出操作相同,从严格意义上讲并不是一个动作。在实践中it just invokes foreachRDD

dstream.foreachRDD(rdd => rdd.sparkContext.runJob(rdd, writer.write _))

which in turn

  

向此DStream中的每个RDD应用一个函数。这是一个输出运算符,因此“ this” DStream将被注册为输出流,并因此实现。

差异是细微的,但很重要-已注册了操作,但实际执行是在不同的上下文中进行的。

这意味着在您调用saveToCassandra时不会出现运行时失败。

正如已经指出的,tryTry如果直接应用于动作,则将包含驱动程序异常。因此,例如,您将saveToCassandra重新实现为

dstream.foreachRDD(rdd => try { 
  rdd.sparkContext.runJob(rdd, writer.write _) 
} catch {
  case e: Exception => log.error("Error in saving data in Cassandra" + e. getMessage, e)
})

尽管当前批次将全部或部分丢失,但流应该能够继续进行。

重要的是要注意,这与捕获原始异常不同,原始异常将在日志中被抛出,未捕获和可见。要从源头上发现问题,您必须直接在writer中应用try / catch块,并且当您执行无法控制的代码时,这显然不是一个选择。 / p>

带走消息是(已在此线程中声明)-请确保清理数据以避免已知的故障源。

答案 1 :(得分:-1)

问题是您没有捕获到您认为的异常。您拥有的代码将捕获驱动程序异常,实际上,像这样构造的代码将做到这一点。

但这并不意味着

  

程序永远都不会停止。

当驱动程序故障(可能由致命的执行程序故障导致)被包含在内且驱动程序可以正常退出时,流已经消失了。因此,您的代码将退出,因为没有更多的流可以运行。

如果有问题的代码在您的控制之下,则应将异常处理委托给任务,但是对于第3方代码,则没有此类选项。

相反,您应先验证数据并删除有问题的记录,然后再将这些记录传递给saveToCassandra