Oozie Spark on YARN requirement failed

軟件環境:

CDH:5.7.3;Oozie:4.1.0-CDH5.7.3 ; Spark:1.6.0-cdh5.7.3-hadoop2.6.0-cdh5.7.3 ; Hadoop:hadoop2.6.0-cdh5.7.3(HDFS 採用HA方式);

問題描述:

在使用CDH5.7.3版本的時候,發起一個Oozie工作流,該工作流使用Spark On YARN的方式提交一個Spark程序,但是在Oozie中該程序運行失敗,同時找到YARN監控中對應的任務,發現出現下面的錯誤(該Spark任務如果使用spark-submit --master yarn的方式是可以提交併正確運行的):


解決思路:

1. 首先就是各種網上找

不過並沒有找到相關的信息,找到一些,不過和我出現的問題有點不一樣(有個論壇上好像說是bug);

2. 查看源碼

準備環境,查看其源碼,看是哪個地方報的Requirement failed,在上圖中紅色框裏面就是對應的內容,其源代碼如下所示:


而require函數如下:

這裏面就會有提示 requirement failed
那麼也就是說在473行中的localizedPath等於null,這樣子,那麼473行的require函數驗證就不會通過,就會報這個異常了;localizedPath是怎麼得到的呢?
這個是通過distribute函數得到,distribute函數裏面的參數file其實是用戶提交的參數addJars、files、archives這三個參數,分別對應哪些內容呢?(以下是YARN任務日誌截圖):

從上面的提交參數來看,由於files和archives都是null,那麼就肯定不是這兩個參數的問題,那jars這個參數是怎麼得到的呢?這個參數是oozie的sharelib裏面的jar,但是這個參數值往後一直找發現其結果很多,而且還有以file開頭的,也就是說也會有本地的jar包;如下:

那麼肯定就是這裏的問題了!
初步猜測,可能是Oozie在網這個裏面添加jar包的時候添加多了,所以纔會有本地的jar包被添加,那麼試着修改job.properties裏面的參數:
#oozie.use.system.libpath=true
oozie.libpath=${nameNode}/user/oozie/share/lib/lib_20161222004831/spark
採用第二行的方式,而非第一行的方式(第二行中的lib_2016...是時間戳,每個集羣應該不一樣);
結果使用這種方式依然不行,還是報同樣的錯誤;
那麼看看到底是處理哪個jar包路徑出問題呢?怎麼做?
修改Client源碼的第473行,添加一行打印:
val cachedSecondaryJarLinks = ListBuffer.empty[String]
    List(
      (args.addJars, LocalResourceType.FILE, true),
      (args.files, LocalResourceType.FILE, false),
      (args.archives, LocalResourceType.ARCHIVE, false)
    ).foreach { case (flist, resType, addToClasspath) =>
      if (flist != null && !flist.isEmpty()) {
        flist.split(',').foreach { file =>  // add distinct operation to avoid multiple same jars
          val (_, localizedPath) = distribute(file, resType = resType)
          println("fansy: ---->file:"+file)
          require(localizedPath != null)
          if (addToClasspath) {
            cachedSecondaryJarLinks += localizedPath
          }
        }
      }
    }
然後再次查看日誌:


發現:1. 提示的行數變爲474了,說明源碼修改成功;2 . 在提示中發現到file:/opt/cloudera/parcels/CDH/lib/hadoop-mapreduce/jets3t-0.9.0.jar
提示完畢,但是這個文件並不是最後一個addJars參數文件,其後還有很多文件,如下:

爲什麼會是這個文件結束呢?
查找這個文件出現的次數:

會發現這個文件出現了2次,查詢這個文件之後的文件發現都是出現了2次,但是之前的文件只出現了一次,這也就是說:
添加的addJars參數有些路徑是重複的!
重複的路徑經過distribute函數,處理後,第一個參數會被添加,但是重複的其實就沒有必要添加了,所以distribute返回的是localizedPath就是null,這也就是爲什麼驗證通不過的原因所在了。

解決方案:

1. 修改源碼:

源碼中的addjar參數既然得到的有重複的,那麼去重就可以了,如下:
val cachedSecondaryJarLinks = ListBuffer.empty[String]
    List(
      (args.addJars, LocalResourceType.FILE, true),
      (args.files, LocalResourceType.FILE, false),
      (args.archives, LocalResourceType.ARCHIVE, false)
    ).foreach { case (flist, resType, addToClasspath) =>
      if (flist != null && !flist.isEmpty()) {
        flist.split(',').distinct.foreach { file =>  // add distinct operation to avoid multiple same jars
          val (_, localizedPath) = distribute(file, resType = resType)
          println("fansy: ---->file:"+file)
          require(localizedPath != null)
          if (addToClasspath) {
            cachedSecondaryJarLinks += localizedPath
          }
        }
      }
    }
編譯該源碼(如果自己編譯記得去掉那行打印),得到其class,如下:

2. 替換Jar包

(上傳、刪除注意HDFS權限)
把HDFS上的oozie的sharelib下包含Client的jar包下載下來,這個jar包在我集羣中的位置是(注意時間戳):
/user/oozie/share/lib/lib_20161222004831/spark/spark-yarn_2.10-1.6.0-cdh5.7.3.jar
把這個jar包先下載到linux,然後下載到windows;接着刪掉HDFS上的該jar包:
hdfs dfs -rm -r /user/oozie/share/lib/lib_20161222004831/spark/spark-yarn_2.10-1.6.0-cdh5.7.3.jar
在windows裏面使用winRAR打開下載的spark-yarn_2.10-1.6.0-cdh5.7.3.jar包,並使用編譯後的Client的所有class替換對應的class;替換完成後得到該spark jar(可以在這裏下載 http://download.csdn.net/detail/fansy1990/9720059 )

然後把該替換後的jar包上傳到linux,再通過linux上傳到HDFS:
hdfs dfs -put spark-yarn_2.10-1.6.0-cdh5.7.3.jar /user/oozie/share/lib/lib_20161222004831/spark/
再次運行,發現Oozie任務成功運行:

總結:

1. 在使用一些多個框架技術的時候,如果找不到資料解決問題,那麼最直接的方式是查看源碼;
2. bug無處不在!


分享,成長,快樂

轉載請註明blog地址:http://blog.csdn.net/fansy1990





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章