記2018最後一次問題診斷-Spark on Yarn所有任務執行失敗
2018的最後一個工作日,是在調式和診斷問題的過程中度過,原本可以按時下班,畢竟最後一天了,然鵝,確是一直苦苦掙扎。
廢話不多說,先描述一下問題:有一套大資料環境,是CDH版本的,總共4臺機子,我們的應用程式與大資料叢集之前已經整合完畢,除錯沒有問題,可以執行Spark任務。而與這個叢集整合是17年下半年的事了,這次升級後,發現無法正確的執行任務,不管是程式提交的還是用示例程式SparkPi,或者手動用spark-submit提交,都是執行失敗,且Yarn框架排程執行兩次。主要錯誤提示如下:
Diagnostics: java.lang.NoSuchMethodError: org.apache.commons.io.FileUtils.isSymlink(Ljava/io/File;)Z
截圖如下:
sprak-submit提交客戶端日誌截圖
yarn:8088任務監控頁面任務(與上圖不是一個任務,但錯誤資訊一致)
其實,從任務日誌錯誤提示,可以看出,肯定是載入了低版本的包,用了高版本的方法,NoSuchMethod異常再也熟悉不過了,這一點確信後,就需要找這個包在哪裡?FileUtils類屬於commons-io包,目前有1.4和2.4版本的,其中,1,4中的FileUtils類確實沒有isSymlink方法。好了,基本可以確認,程式在使用了這個commons-io-1.4.jar包。
雖然問題確認,但是還是讓人很頭疼,因為我可以確認,我們自己的應用程式中,只用了2.4的包。為了排序一些常規影響,我們分別使用cdh自帶的sparka提交、使用最簡單的SparkPi來執行,但都執行失敗,並且我還寫了一個搜尋類所在的包的工具,來執行排查問題。
package com.meritdata.search.tool; import java.io.PrintStream; import java.security.CodeSource; import java.security.ProtectionDomain; public class Utils { public static void search(String name) { try { Class clazz = Class.forName(name); ProtectionDomain pd = clazz.getProtectionDomain(); CodeSource cs= pd.getCodeSource(); System.out.println(name + " location: " + cs.getLocation()); } catch (Throwable e) { e.printStackTrace(); } } }
package com.meritdata.search.tool; public class Search { public static void main(String[] args) { String name = args[0]; Utils.search(name); } }
這是最先開始使用的程式碼,想驗證當前任務載入的包是不是有其他的版本,使用提交命令:
%SPARK_HOME%>.\bin\spark-submit.cmd --master --deploy cluster --files hive-site.xml --class com.meritdata.search.tool.Search search.tool-0.0.1-SNAPSHOT.jar org.apache.commons.io.FileUtils
這個任務執行的結果,列印的是commons-io-2.4.jar。確認後再想,是不是其他地方引用,而這個demo比較簡單,沒有使用到,因為載入順序不一樣,可能會影響。所以,又完善了一下程式:
package com.meritdata.search.tool; import java.util.Collections; import org.apache.spark.sql.Dataset; import org.apache.spark.sql.Encoders; import org.apache.spark.sql.SparkSession; import org.apache.spark.sql.SparkSession.Builder; public class SparkDemo { public static void main(String[] args) { try { SparkSession spark = SparkSession.builder().appName("SparkDemo").enableHiveSupport().getOrCreate(); Dataset dataset = spark.createDataset(Collections.singletonList("test"), Encoders.STRING()); dataset.show(); spark.sql("SELECT explode(Array(\"a\", \"b\", \"c\")) as v ").show(); } catch (Throwable e) { e.printStackTrace(); } String name = args[0]; Utils.search(name); } }
因為實際中,要使用spark,必須初始化SparkSession,這樣執行完成spark的程式碼後,再看看列印的包名稱。但是結果令人意外,在初始化SparkSession的時候,任務就異常了,錯誤資訊如開頭提示。這下,我終於確認,是Yarn服務載入了不該載入的jar包,這下,就要排查yarn載入的包了,除過應用自己,yarn還要載入預設的包,hadoop的,hdfs的,yarn的包,配置項為 yarn.application.classpath, 在CDH的配置介面可以搜尋到,有預設配置,會載入hadoop的一些基礎程式包。首先想到的是,肯定是這個路徑下面載入了低版本的包,想清空試試執行,結果還不行,因為有預設值,不填寫每用,後來才想到的,因為當時已經除錯的懵逼了。
發現不過後,想著去伺服器上面,看看那些地方都有1.4的包,使用搜索命令:
find / -name commons-io-*.jar -type f
搜尋結果如圖:
在大資料叢集的某個節點搜尋到的結果
從搜尋結果來看,在cdn的jars下面有個1.4的包,我想,會不會是這樣包引起的呢?但是,我在其他的環境中也發現這個包,不可能是這個包引起的,要不然,都得有問題。既然這個包沒有影響,任務載入的包也是正確的,哪到底是哪裡的影響了任務的執行?
此時,這個問題已經搞得人頭疼,嘗試了卻沒有發現問題,明明很簡單,就包衝突,卻無法解決。在領導的提示下,替換1.4中的FileUtils類,看看到底是不是這個包的問題,也不管了,只能試試了,司馬當活馬醫。修改完成,打包,在四個節點搜尋所有的1.4包,準備替換。
突然,發現了一個讓人驚喜的意外,在大資料叢集的某個節點,在Hadoop的子目錄,搜尋到了一個1.4的包,而且不是軟連結。
從搜尋結果可以看出來,在執行的時候,每個任務下臨時目錄會複製jar包,hadoop/lib/commons-io-1.4.jar就是這個原因,檢視其他節點,均為有類似情況。毫無疑問,刪除這個包,重啟叢集,執行demo,成功,終於鬆了一口氣。不知道是什麼原因導致,現場環境複雜,所以也沒辦法追究,也沒有必要,問題出現,就得解決。其實,很早之前,就應該檢查四個節點,這樣的話,就不會在那瞎想,可以儘早的發現異常包。
由於是客戶現場,除錯不方便,同事也比較辛苦,在現場的滋味,我深有體會。問題雖然簡單,但是對整理的瞭解和除錯方法也是很重要的,否則,會做很多無用功。
僅此來紀念和告別2018的辛勤工作,2019繼續奮發前行,讓自己更強。
本文地址:https://www.cnblogs.com/flowerbirds/p/10205185.html