Spark相關問題的故障排除

Spark的執行模型

我們遇到的大多數必須處理的問題需要先理解代碼的執行環境。Spark作業是在分佈式數據集上執行並行操作的驅動程序。爲了解決問題需要理解代碼的不同部分在哪裏運行。
下面是官網的WordCount例子:

file = spark.textFile("hdfs://...")

file.flatMap(line => line.split(" "))
    .map(word => (word, 1))
    .reduceByKey(_ + _)

下圖是官網的架構圖:
這裏寫圖片描述

我們知道,對於Spark開發的分佈式應用程序,和寫普通的scala程序基本類似。所以這時候往往會陷入一些誤區:
在Spark開發的應用程序的對象裏,我給他們分爲2類對象:
1、閉包內的對象:即在類似map,filter,reduceByKey這樣的閉包內的對象,通過會有一個函數映射。
2、閉包外的對象:反之,即閉包外的對象。
這2類對象其實是混雜在Driver和Worker裏的,即並不是所有對象都會隨着程序序列化到Worker裏。

Spark出現NotSerializableException

如果強制將一個不支持序列化的對象方到閉包裏,會報異常NotSerializableException

object MyFirstSparkJob {
  def main(args: Array[String]) {
    val ssc = new StreamingContext(args(0), "BeaconCount", Seconds(1))
    val parser = new JSONParser // <-- INSTANTIATED HERE

    val lines = ssc.textFileStream("beacons.txt")
    lines.map(line => parser.parse(line)) // <-- IN THE CLOSURE
    lines.foreach(line => println(line))

    ssc.start()
  }
}

對象JSONParser在並行操作的閉包中被引用,並被序列化到worker。但是JSONParser類不是可序列化的,會導致錯誤。爲了解決這個問題,我們需要將JSONParser實現序列化,或者將對象移動到閉包中進行創建。

Spark任務執行特別慢並且使用的是單例線程工作

在並行的閉包操作中引用單例對象將會阻礙進程,因爲這些引用將在Driver程序中發生,

object JSONParser {
  def parse(raw: String): String = ...
}

object MyFirstSparkJob {
  def main(args: Array[String]) {
    val ssc = new StreamingContext(args(0), "BeaconCount", Seconds(1))

    val lines = ssc.textFileStream("beacons.txt")
    lines.map(line => JSONParser.parse(line))
    lines.foreach(line => println(line))

    ssc.start()
  }
}

這和上一個例子的代碼類似,但是這裏的JSONParser對象現在是在我們的Driver程序範圍內創建的單例對象。這個對象不會再worker的上下文中傳遞,所以Spark只會在驅動程序中執行引用該對象的代碼,這對job會造成瓶頸。
爲了解決這個問題,你可以把這個對象變成一個可以傳遞給worker進程的可序列化的類。或者你可以使用廣播變量在每個worker的上下文中使這個對象可用。

Spark報java.lang.IllegalArgumentException:shuffle id XXXX registered twice

關於異常捕捉,如果在Spark Driver程序中對job的異常沒有捕捉的話會導致java.lang.IllegalArgumentException: Shuffle Id Nnnn Registered Twice

發佈了14 篇原創文章 · 獲贊 13 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章