記錄一些常見的 Spark 做業裏的 troubleshooting。sql
在 shuffle 過程當中,reduce 端在拉取 map 端的數據時,每一個 task 會有本身的 緩衝區用來存放每次拉取的數據,這個緩衝區默認是 48M。shell
若是 map 端產生的數據量很是大,而且 map 端的寫入數據很是快,那麼這時候 reduce 端的全部 task 的緩衝區可能會出現滿負荷存儲,每一個 task 的緩衝區都會被寫滿,那麼會致使 task 在計算過程當中讀取的數據量很大,但每一個 executor 在當前 JVM 進程中分配的內存是死的(0.2佔比),這時候大量的 task 計算產生的對象極可能會撐爆內存,致使 OOM。網絡
這時候咱們能夠經過調小 reduce 端的緩衝區內存大小,讓 task 多拉取幾回,多些網絡傳輸的性能消耗,但能夠保證 reduce 端的內存夠用。app
Spark 做業中有時會出現的一種狀況:shuffle file not found,仍是挺常見的。並且有的時候,出現這種狀況之後,會從新去提交stage、task。從新執行一遍,發現就行了。沒有這種錯誤了。函數
這是由於前一個 stage 在 shuffle 時候內存消耗太大,頻繁的 gc,每當觸發 gc 的時候,整個 JVM 進程都會中止做業。而在這個時候下一個 stage 的 executor 要拉取須要用的數據,這時候就會拉不到,這時候會嘗試等待一會,再次拉取,有時候恰好等待時間後,前一個 stage 的 gc 結束,這時候就能拉到數據了。性能
這種狀況能夠調整這兩個參數:spa
1,spark.shuffle.io.maxRetries
shuffle 拉取失敗後重試的次數,默認是 3 次;code
2,spark.shuffle.io.retryWait
每次重試拉取文件的時間間隔,默認是 5s;對象
一個 Yarn 集羣中可能已經跑了一個 spark 做業,這時候你又提交一個 spark 做業,兩個 spark 做業設置的資源恰好等於或者稍小於整個集羣的資源,這時候很容易致使跑不了第二個 spark 做業,由於 spark 做業跑起來以後耗費的資源頗有可能大於咱們在 shell 腳本里分配的資源。接口
爲了防止這樣的事情發生,有這幾種方案:
1,在 J2EE 中作限制,同時只能提交一個 Spark 做業到 Yarn 集羣上去執行,這樣確保一個 Spark 做業的資源夠用就行;
2,使用隊列的方式執行 Spark 做業,保證每一個 Spark 做業分配的資源到最大化,確保每一個 Spark 做業在最短的時間內執行完畢;
用 client 模式提交 Spark 做業時,本地打印的 log 中出現相似於 Serializable 之類的報錯。這種報錯是因爲某類沒有實現序列化接口致使的錯誤。
常見的須要序列化的地方有這兩個:
1,算子函數彙總使用到外部的自定義類型的變量;
2,若是要將自定義的類型,做爲 RDD 的元素類型,這個類型也要實現序列化接口;
生產環境下若是使用 Yarn-client 模式跑 Spark 做業,因爲 driver 進程跑在本地設備上,大量的數據傳輸會致使本地設備的網卡流量十分的大。
因此生產環境要使用 Yarn-cluster 模式。
有時候,運行了一些包含了 Spark sql 的 Spark 做業,可能會碰到在 Yarn-client 模式下正常運行,但在 Yarn-cluster 模式下,會報 JVM 的 PermGen(永久代)的內存溢出問題。
由於 Yarn-client 模式下,driver 是運行在本地設備上的,Spark 使用的 JVM 的 PermGen 的配置是本地的 spark class 文件,JVM 的永久帶大小爲 128M。但在 Yarn-cluster 模式下,drvier 是運行在 Yarn 集羣的某個節點上的,默認的大小是 82M。
Spark sql 的內部有不少複雜的 SQL 語義解析,語法數轉換等等,特別複雜。在這種狀況下,若是 sql 寫的比較發咋的話,會致使內存的消耗,對永久代的佔用會比較大,容易超過 Yarn 集羣上的設置的默認值。
解決方案:
spark-submit腳本中,加入如下配置便可:
--conf spark.driver.extraJavaOptions="-XX:PermSize=128M -XX:MaxPermSize=256M"
這個就設置了 driver 永久代的大小,默認是 128M,最大是 256M。那麼,這樣的話,就能夠基本保證你的 Spark 做業不會出現上述的 yarn-cluster 模式致使的永久代內存溢出的問題。