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





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