[英]Exception is not caught by the try catch block
我正在將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塊,但是程序卻停止了。 為什么未捕獲到異常?
要了解失敗的根源,您必須承認DStreamFunctions.saveToCassandra
與DStream
輸出操作通常相同,從嚴格意義上講,這不是一個操作。 實際上, 它只是調用foreachRDD
:
dstream.foreachRDD(rdd => rdd.sparkContext.runJob(rdd, writer.write _))
依次 :
將函數應用於此DStream中的每個RDD。 這是一個輸出運算符,因此“ this” DStream將被注冊為輸出流,並因此實現。
差異是微妙的,但很重要-操作已注冊,但實際執行發生在不同的上下文中,在稍后的時間點。
這意味着在調用saveToCassandra
時不會出現運行時失敗。
如前所述,如果直接應用於動作,則try
或Try
將包含驅動程序異常。 因此,例如,您可以將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
塊,這顯然不是您執行代碼時無法控制的選擇。
帶走消息是(已在此線程中聲明)-請確保清理數據以避免已知的故障源。
問題是您沒有捕獲到您認為自己有的異常。 您擁有的代碼將捕獲驅動程序異常,實際上,像這樣構造的代碼將做到這一點。
但是,這並不意味着
該程序永不停止。
雖然包含了因執行器致命故障而導致的驅動程序故障,並且驅動程序可以正常退出,但流本身已經消失了。 因此,您的代碼將退出,因為沒有更多的流可以運行。
如果有問題的代碼在您的控制之下,則應將異常處理委派給任務,但是對於第3方代碼,則沒有此類選項。
相反,您應該先驗證數據並刪除有問題的記錄,然后再將這些記錄傳遞給saveToCassandra
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.