暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

基于SPARK SQL 读写ORACLE 的简单案例分析常见问题(五)

偷功 2016-04-27
642

3.4    master为集群的MasterURL+部署模式为Cluster时


CLUSTER部署模式时,Driver在某个节点提交,但却是在集群调度分配的节点上运行。


此时,可以将Driver看成是特殊的Executor,同样由分配的节点运行JVM进程,但对应进程的classpath配置信息(补充说明下,看配置属性的extra名,应该可以知道是附加的,或新增的classpath内容,而不是全部)由各自对应的配置属性进行设置。


CLUSTER部署模式在Drive分配到节点,并在节点上启动,相关属性配置及其作用等和CLIENT部署模式基本一致。这里仅基于配置属性方式针对Driver进行解析。


3.4.1    应用程序提交方式


下面给出两种形式的提交命令:


一、基于REST服务提交方式


$SPARK_HOME/bin/spark-submit  --master spark://nodemaster:6066 \

 --deploy-mode cluster \

 --driver-memory 2g \

 --driver-cores 1 \

 --total-executor-cores 2 \

 --executor-memory 4g \

 --conf "spark.ui.port"=4081 \

 --conf "spark.executor.extraClassPath"="hdfs://nodemaster:8020/tmp/sptest/ojdbc14.jar"\

 --conf "spark.driver.extraClassPath"="hdfs://nodemaster:8020/tmp/sptest/ojdbc14.jar"   \

         --classcom.mb.TestJarwithOracle \

         hdfs://nodemaster:8020/tmp/sptest/Spark15.jar


该方式采用REST服务作为masterurl提交应用程序。对应的值参考8080(默认)监控界面,如下所示:




日志:

Running Spark using the REST applicationsubmission protocol.

16/04/26 13:15:02 INFOrest.RestSubmissionClient: Submitting a request to launch an application inspark://nodemaster:7078.

16/04/26 13:15:03 WARNrest.RestSubmissionClient: Unable to connect to server spark://nodemaster:7078.

Warning: Master endpoint spark://nodemaster:7078was not a REST server. Falling back to legacy submission gateway instead.

16/04/26 13:15:04 WARN util.NativeCodeLoader:Unable to load native-hadoop library for your platform... using builtin-javaclasses where applicable


当REST 服务方式提交尝试失败后,会退回到传统方式进行提交。


二、传统提交方式


$SPARK_HOME/bin/spark-submit  --master spark://nodemaster:7078 \

 --deploy-mode cluster \

 --driver-memory 2g \

 --driver-cores 1 \

 --total-executor-cores 2 \

 --executor-memory 4g \

 --conf "spark.ui.port"=4081 \

 --conf "spark.executor.extraClassPath"="hdfs://nodemaster:8020/tmp/sptest/ojdbc14.jar"\

 --conf "spark.driver.extraClassPath"="hdfs://nodemaster:8020/tmp/sptest/ojdbc14.jar"   \

         --classcom.mb.TestJarwithOracle \

         hdfs://nodemaster:8020/tmp/sptest/Spark15.jar


日志:

Running Spark using the REST applicationsubmission protocol.

16/04/26 13:20:58 INFOrest.RestSubmissionClient: Submitting a request to launch an application inspark://nodemaster:6066.

16/04/26 13:20:58 INFOrest.RestSubmissionClient: Submission successfully created asdriver-20160426132058-0010. Polling submission state...

16/04/26 13:20:58 INFOrest.RestSubmissionClient: Submitting a request for the status of submissiondriver-20160426132058-0010 in spark://nodemaster:6066.

16/04/26 13:20:58 INFO rest.RestSubmissionClient:State of driver driver-20160426132058-0010 is now RUNNING.

16/04/26 13:20:58 INFOrest.RestSubmissionClient: Driver is running on workerworker-20160418110627-192.168.149.95-45661 at 192.168.149.95:45661.

16/04/26 13:20:58 INFO rest.RestSubmissionClient:Server responded with CreateSubmissionResponse:

{

 "action" : "CreateSubmissionResponse",

 "message" : "Driver successfully submitted asdriver-20160426132058-0010",

 "serverSparkVersion" : "1.5.2",

 "submissionId" : "driver-20160426132058-0010",

 "success" : true

}


3.4.2    提交应用之后Driver的分析


两种方式都可以成功提交应用程序,对应在界面会分别增加一个Driver,同时Driver启动后,会和之前Client部署模式的流程一样,提交一个Application(这里的概念对应Executor),对应界面(8080默认端口界面-最下面)有:




两个driver提交的应用如下(8080默认端口界面):



对应下面的Application,配置及其影响和前面是一样的,只是当前的Driver在分配的节点上运行(所有相关路径等概念都改为基于该执行节点)。因此下面仅分析Driver的相关内容。


信息获取相关操作:

1. 点击Driver行所在的Worker,跳转到该Worker监控页面,到最下面,查找与Driver的SubmissionID相同的Driver信息,界面如下所示:



2. 点击对应的stderr日志信息,可以看到Driver的启动命令及其执行日志


3. 查看Driver的启动命令

    a)  对应传统提交方式的日志如下所示:


LaunchCommand: "/usr/java/jdk1.7.0_71/bin/java" "-cp""hdfs://nodemaster:8020/tmp/sptest/ojdbc14.jar:$SPARK_HOME/sbin/../conf/:$SPARK_HOME/lib/spark-assembly-1.5.2-hadoop2.6.0.jar:$SPARK_HOME/lib/datanucleus-api-jdo-3.2.6.jar:$SPARK_HOME/lib/datanucleus-core-3.2.10.jar:$SPARK_HOME/lib/datanucleus-rdbms-3.2.9.jar:/etc/hadoop/conf/""-Xms2048M" "-Xmx2048M""-Dspark.deploy.defaultCores=4""-Dspark.eventLog.enabled=true" "-Dakka.loglevel=WARNING""-Dspark.history.fs.cleaner.maxAge=7d""-Dspark.submit.deployMode=cluster" "-Dspark.executor.memory=4g""-Dspark.executor.extraClassPath=hdfs://nodemaster:8020/tmp/sptest/ojdbc14.jar""-Dspark.executor.extraJavaOptions=-XX:+PrintGCDetails""-Dspark.jars=hdfs://nodemaster:8020/tmp/sptest/Spark15.jar""-Dspark.history.fs.cleaner.enabled=true""-Dspark.master=spark://nodemaster:7078" "-Dspark.driver.supervise=false""-Dspark.driver.extraClassPath=hdfs://nodemaster:8020/tmp/sptest/ojdbc14.jar""-Dspark.app.name=com.mb.TestJarwithOracle""-Dspark.history.fs.logDirectory=hdfs://nodemaster:8020/user/hdfs/sparklogs""-Dspark.driver.memory=2g" "-Dspark.cores.max=2""-Dspark.rpc.askTimeout=10" "-Dspark.eventLog.dir=hdfs://nodemaster:8020/user/hdfs/sparklogs""-Dspark.ui.port=4081""-Dspark.history.fs.cleaner.interval=1d""-Dspark.driver.cores=1" "-XX:MaxPermSize=256m""org.apache.spark.deploy.worker.DriverWrapper""akka.tcp://sparkWorker@192.168.149.95:45661/user/Worker" "$SPARK_HOME/work/driver-20160426131505-0009/Spark15.jar""com.mb.TestJarwithOracle"


    b)  对应REST提交方式的日志如下所示:


Launch Command:"/usr/java/jdk1.7.0_71/bin/java" "-cp" "hdfs://nodemaster:8020/tmp/sptest/ojdbc14.jar:$SPARK_HOME/sbin/../conf/:$SPARK_HOME/lib/spark-assembly-1.5.2-hadoop2.6.0.jar:$SPARK_HOME/lib/datanucleus-api-jdo-3.2.6.jar:$SPARK_HOME/lib/datanucleus-core-3.2.10.jar:$SPARK_HOME/lib/datanucleus-rdbms-3.2.9.jar""-Xms2048M" "-Xmx2048M""-Dspark.deploy.defaultCores=4""-Dspark.eventLog.enabled=true""-Dspark.history.fs.cleaner.maxAge=7d""-Dspark.submit.deployMode=cluster" "-Dspark.executor.memory=4g""-Dspark.executor.extraClassPath=hdfs://nodemaster:8020/tmp/sptest/ojdbc14.jar""-Dspark.executor.extraJavaOptions=-XX:+PrintGCDetails" "-Dspark.jars=hdfs://nodemaster:8020/tmp/sptest/Spark15.jar""-Dspark.history.fs.cleaner.enabled=true""-Dspark.master=spark://nodemaster:7078""-Dspark.driver.supervise=false" "-Dspark.driver.extraClassPath=hdfs://nodemaster:8020/tmp/sptest/ojdbc14.jar""-Dspark.app.name=com.mb.TestJarwithOracle" "-Dspark.history.fs.logDirectory=hdfs://nodemaster:8020/user/hdfs/sparklogs""-Dspark.driver.memory=2g" "-Dspark.cores.max=2""-Dspark.eventLog.dir=hdfs://nodemaster:8020/user/hdfs/sparklogs""-Dspark.ui.port=4081""-Dspark.history.fs.cleaner.interval=1d" "-Dspark.driver.cores=1""-XX:MaxPermSize=256m" "org.apache.spark.deploy.worker.DriverWrapper""akka.tcp://sparkWorker@192.168.149.95:45661/user/Worker" "$SPARK_HOME/work/driver-20160426132058-0010/Spark15.jar""com.mb.TestJarwithOracle"


(暂时不考虑两者的差异,仅关注Driver进程相关的内容。)


下面对其中比较重要的几个部分进行分析:


1. 其中,启动的JVM进程主类为"org.apache.spark.deploy.worker.DriverWrapper",在"-cp"后加入了hdfs://nodemaster:8020/tmp/sptest/ojdbc14.jar,这里对应的是提交命令中的--conf"spark.driver.extraClassPath"配置属性(可通过修改设置的路径进行验证)。

在该启动命令(提交命令的配置参数)中,ojdbc14.jar路径为hdfs,因此无法识别,在driver部分的逻辑代码执行时会抛出异常。对应日志在该LaunchCommand:命令后面。因此"spark.driver.extraClassPath"配置属性中设置的路径应该对应当前节点(由于是调度分配的,对应就意味着应该是在集群中各个节点都进行部署)的路径,并且路径下有所需jar包。


2. 对应的spark.driver.extraClassPath、spark.executor.extraClassPath等会继续作为Driver的参数传入(和Client部署模式下直接执行Driver一样)


3.  "-Dspark.jars=hdfs://nodemaster:8020/tmp/sptest/Spark15.jar":对应提交时的主资源。


4. "$SPARK_HOME/work/driver-20160426132058-0010/Spark15.jar":work是默认的工作目录,driver-20160426132058-0010是当前Driver对应的Submission ID,在该目录中会下载Driver执行所需的Jar包,这里对应主资源Spark15.jar。


此时,需要注意的是,当CLUSTER部署模式时,如果使用的主资源是本地路径,如以下命令:


$SPARK_HOME/bin/spark-submit  --master spark://nodemaster:6066 \

 --deploy-mode cluster \

 --driver-memory 2g \

 --driver-cores 1 \

 --total-executor-cores 2 \

 --executor-memory 4g \

 --conf "spark.ui.port"=4081 \

 --conf "spark.executor.extraClassPath"="hdfs://nodemaster:8020/tmp/sptest/ojdbc14.jar"\

 --conf "spark.driver.extraClassPath"="$SPARK_HOME/thirdlib/ojdbc14.jar"   \

         --classcom.mb.TestJarwithOracle \

         /tmp/test/Spark15.jar


其中红色部分对应为主资源jar包,采用本地文件系统的路径。执行时,Driver端输出的错误信息如下所示(对应界面的Driver状态为Error):


java.io.FileNotFoundException:/tmp/test/Spark15.jar (No such file or directory)

        java.io.FileInputStream.open(NativeMethod)

       java.io.FileInputStream.<init>(FileInputStream.java:146)

        org.spark-project.guava.io.Files$FileByteSource.openStream(Files.java:124)

       org.spark-project.guava.io.Files$FileByteSource.openStream(Files.java:114)

       org.spark-project.guava.io.ByteSource.copyTo(ByteSource.java:202)

        org.spark-project.guava.io.Files.copy(Files.java:436)

       org.apache.spark.util.Utils$.org$apache$spark$util$Utils$$copyRecursive(Utils.scala:514)

       org.apache.spark.util.Utils$.copyFile(Utils.scala:485)

       org.apache.spark.util.Utils$.doFetchFile(Utils.scala:562)

        org.apache.spark.util.Utils$.fetchFile(Utils.scala:369)

        org.apache.spark.deploy.worker.DriverRunner.org$apache$spark$deploy$worker$DriverRunner$$downloadUserJar(DriverRunner.scala:150)

       org.apache.spark.deploy.worker.DriverRunner$$anon$1.run(DriverRunner.scala:79)


在DriverRunner启动后,调用downloadUserJar,下载所需jar包,但此时使用本地文件系统的路径,对应的就需要在Driver当前执行节点上的该路径下存在该jar包(当前未部署),因此报异常:java.io.FileNotFoundException:/tmp/test/Spark15.jar。


因此,对应在CLUSTER部署模式时,需要注意提交应用程序对应的主资源的配置:


1. 将主资源类似于其他的第三方jar包(如Oracle驱动类库的jar包)部署到集群中;

2. 使用HDFS这类文件系统,可以下载到本地工作目录。


4总结


通过配置classpath,为JVM加载类时提供搜索路径。


在分布式计算集群中,需要注意JVM进程是在哪台节点上启动,对应节点上的classpath下是否部署了所需的jar包(针对jar包以本地路径的形式,即与具体节点相关的路径)。


因此总结起来有以下两点:

1. 是否为对应JVM进程指定了classpath;

2. 在各个进程的classpath路径下是否放置了所需的jar包。放置的方式可以有两种:

    a)  一种是Spark框架提供的自动放置到classpath的方式;

    b)  一种手动在集群中部署的方式;


这里指的路径,表示的是该JVM进程能够读取的路径,比如本地文件系统路径、hdfs路径,其中本地文件系统路径是针对本节点的,这点在分布式集群中尤其要注意。



文章转载自偷功,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论