1. 程式人生 > >記2018最後一次問題診斷-Spark on Yarn所有任務執行失敗

記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