在Windows下程序通过SparkLauncher执行Spark应用好多坑

34 篇文章 1 订阅
14 篇文章 1 订阅

(一)代码提交Spark应用

1.1 spark-submit命令

之前例子都是通过命令🔗提交spark应用到集群并执行。
实际工作中需要流程能自动跑,并且能看到spark应用在集群中执行的状态。
当然不希望用命令来提交任务应用,好在spark提供了程序操作的方式【SparkLauncher】。

1.2 SparkLauncher (Java项目)

1.2.1 pom.xml

需要添加依赖:

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-launcher_2.13</artifactId>
            <version>3.2.0</version>
        </dependency>

1.2.2 Java代码

需要引入包:

import org.apache.spark.launcher.SparkAppHandle;
import org.apache.spark.launcher.SparkLauncher;

然后参考🔗官网文档开始调用:

		SparkLauncher aL = new org.apache.spark.launcher.SparkLauncher();
		aL.setMaster(MASTER)
				.setAppResource(APPPath)//完整的地址比如("hdfs://vm00:9000/bin/xxx-yy.jar")
				.setMainClass(MAINCLASS)//主类名称("org.yourcompany.yourapp")
				.setDeployMode("client")
				.setConf(SparkLauncher.DRIVER_MEMORY, "2g")
				.setConf(SparkLauncher.EXECUTOR_MEMORY,"2g")
				.redirectOutput(AppOut)
				.redirectError(AppErr)
		;
		aL.addAppArgs(youapp_args_list);

		SparkAppHandle aH = aL.startApplication(new SparkAppHandle.Listener() {
			@Override
			public void stateChanged(SparkAppHandle sparkAppHandle){
				if (sparkAppHandle.getState().isFinal()) {
					if (!sparkAppHandle.getError().equals(Optional.empty())) {
						CrossLog.MyLog(TNU.LogType.WARNING,"警告: "+sparkAppHandle.getError().toString());
					}
					countDownLatch.countDown();
				}
				CrossLog.MyLog(TNU.LogType.INFO,"状态变化: " + LastState[0] + (sparkAppHandle.getAppId()==null?"":" ("+ sparkAppHandle.getAppId()+")"));
			}
			@Override
			public void infoChanged(SparkAppHandle sparkAppHandle) {
				CrossLog.MyLog(TNU.LogType.INFO,"信息接收: " + sparkAppHandle.getState().toString() + (sparkAppHandle.getAppId()==null?"":" ("+ sparkAppHandle.getAppId()+")"));
			}
		});
		CrossLog.MyLog(TNU.LogType.INFO,"已提交任务...");
		countDownLatch.await();

如果不关心执行状态,可以不用startApplication,而是launch得到一个Process,然后等它结束。

	Process spark = aL.launch();
    spark.waitFor();

当然也可以读被提交应用的输出。
无论是重定向到文件的日志,还是Process的标准/错误输出。
这样才能更及时的看到应用运行的情况。

1.2.3 处理应用日志

⚠️ 如果不做下面这3项,也能运行,但你的提交的Spark应用日志会显得乱七八糟。

A)去掉日志中的 org.apache.spark.launcher.OutputRedirector
在launcher程序的开头:

System.setProperty("java.util.logging.SimpleFormatter.format","%5$s%6$s%n");

这样就不会看到一大堆redirect了:

一月 05, 2022 11:04:36 上午 org.apache.spark.launcher.OutputRedirector redirect
INFO: ����XXXYYYZZZ
一月 05, 2022 11:04:47 上午 org.apache.spark.launcher.OutputRedirector redirect
INFO: ����XXXYYYZZZ
一月 05, 2022 11:04:54 上午 org.apache.spark.launcher.OutputRedirector redirect
INFO: ���XXXYYYZZZ
一月 05, 2022 11:05:01 上午 org.apache.spark.launcher.OutputRedirector redirect
INFO: ���XXXYYYZZZ

B)重定向被提交应用日志顺便解决中文乱码
并且像上面SparkLauncher代码一样,重定向到文件(或者Logger)。

				.redirectOutput(AppOut)
				.redirectError(AppErr)

这样被调用的Spark应用的输出信息和错误信息,我们就可以得到了。
当然不重定向也能得到,但信息会直接打印到你的标准输出上。。。

C)将被提交Spark应用的日志减少
考虑到Spark环境不方便随意修改……
我们在被提交的应用前面加上:

Logger.getLogger("org").setLevel(Level.ERROR);

否则就算重定向了日志,日志内容还是会太多了。注意这段是说:
被提交的应用!
被提交的应用!!
被提交的应用!!!

(二)Windows环境准备

代码写好了,但是从集群外,特别是Windows下运行还需要做一些准备。

2.1 Hadoop环境

我的Spark访问的文件都在Hadoop里,先准备好Windows的Hadoop吧。
🔗官网下载 hadoop-3.3.1.tar.gz ,解压到C:\hadoop。
设置环境变量:

HADOOP_HOME=C:\hadoop\
HADOOP_COMMON_LIB_NATIVE_DIR=C:\hadoop\lib\native\
HADOOP_OPTS="-Djava.library.path=C:\hadoop\lib\"

然后你会发现根本没用……😓

2.1.1 Hadoop on Windows

查阅🔗官网关于Windows下问题的WIKI发现:

Problems running Hadoop on Windows

Hadoop requires native libraries on Windows to work properly -that includes to access the file:// filesystem, where Hadoop uses some Windows APIs to implement posix-like file access permissions.
This is implemented in HADOOP.DLL and WINUTILS.EXE.
In particular, %HADOOP_HOME%\BIN\WINUTILS.EXE must be locatable.
If it is not, Hadoop or an application built on top of Hadoop will fail.

How to fix a missing WINUTILS.EXE
You can fix this problem in two ways

  1. Install a full native windows Hadoop version. The ASF does not currently (September 2015) release such a version; releases are available externally.
  2. Or: get the WINUTILS.EXE binary from a Hadoop redistribution. There is a repository of this for some Hadoop versions on github.

Then

  1. Set the environment variable %HADOOP_HOME% to point to the directory above the BIN dir containing WINUTILS.EXE.
  2. Or: run the Java process with the system property hadoop.home.dir set to the home directory.

简单说就是你需要去下载上面提到的github项目的winutils执行程序,并放置在【%HADOOP_HOME%/bin】目录下。
官方似乎不准备支持Windows了。

2.1.2 Unable to load native-hadoop library for your platform

后面运行的时候可能还会看到下面的错误(⚠️ 不管它也行):

WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable

感到莫名其妙,因为前面环境变量明明都设置好了啊???
其实只需要把【%HADOOP_HOME%/bin】我这里是【C:\hadoop\bin】加入系统path就好了。
在这里插入图片描述

2.2 Spark环境

🔗官网下载 spark-3.2.0-bin-hadoop3.2.tgz ,解压到C:\spark。
设置环境变量:

SPARK_HOME=C:\spark\

嗯,好像应该OK了。
不过还是会有一个警告:

WARN ProcfsMetricsGetter: Exception when trying to compute pagesize, as a result reporting of ProcessTree metrics is stopped

在被提交的应用中设置 “spark.executor.processTreeMetrics” 为 false,就没这个警告了。
参考🔗这位同学的文章,感觉Spark也放弃Windows了吧(这是吐槽而已,官方写着支持的)。。。

(三)提交Java应用

语言Java和scala开发的应用都是jar包,在JVM下面执行,算是一类吧。
前面步骤没问题的话已经可以正常提交运行了。

但是最后会有警告(⚠️ 不管它也行):

java.lang.RuntimeException: java.io.IOException: Failed to delete: C:\Windows\Temp\spark-a0608edd-1a5e-49a3-a6e0-3de9925b1335\XXYYZZZ.jar

这个问题似乎是目前Spark版本的bug?
查了各种讨论,设环境变量,设置目录权限,都没有用。
只能眼不见心不烦,编辑或从模板拷一份【C:\spark\conf\log4j.properties】,加入下面两行:

log4j.logger.org.apache.spark.util.ShutdownHookManager=OFF
log4j.logger.org.apache.spark.SparkEnv=ERROR

屏蔽掉相关错误的显示。
可是那些临时文件依然没有被删掉……
只能定期手动处理。
参考:🔗链接1🔗链接2

(四)提交Python应用

⚠️ 这个小问题未解决,先记录一下,没发现问题在哪。
Python应用做了和Java同样的设置,但上面的那个警告却还在。

Java代码:

SparkSession.Builder sparkB = SparkSession.builder()
                .appName(DisPlayAppName)
                .config("spark.executor.processTreeMetrics",false);

Python代码:

sparkB = SparkSession.builder
				.appName(DisPlayAppName)
				.config("spark.executor.processTreeMetrics", False)

会有警告:

WARN ProcfsMetricsGetter: Exception when trying to compute pagesize, as a result reporting of ProcessTree metrics is stopped

3.1 Spark与Python版本支持

查看🔗官网说明

Python 3.6 support is deprecated as of Spark 3.2.0. Java 8 prior to version 8u201 support is deprecated as of Spark 3.2.0. For the Scala API, Spark 3.2.0 uses Scala 2.12.

恰好CentOS7 如果直接 yum install python 则是3.6.8。
那么用Python3.6运行Spark3.2.0时会有警告(虽然能用):
不想看到这个警告则需要升级Python版本。

C:\spark\python\lib\pyspark.zip\pyspark\context.py:238: FutureWarning: Python 3.6 support is deprecated in Spark 3.2.

同时集群Python版本,以及提交的那台机器Python版本,需要保持一致,呃,至少在大版本上一致。
版本不一致无法运行且会抛出相关异常。

(找不到记录了,无图)

3.2 安装Python(Windows)

🔗Python官网直接下载编译好的安装包,双击安装,就可以了。
💡 版本请与Linux集群一致!

对了,Windows下只有python命令,没有python3命令,
所以最简单就是到安装目录下,拷贝一份python.exepython3.exe

Windows可能需要重启一下。

3.3 安装Python(Linux)

目前CentOS7用yum安装python 是3.6.8。
而Ubuntu20用apt安装python是3.8.10。
🔗Python官网并没有提供Linux下的二进制程序。。。
那么只能下载源码【Python-3.10.1.tgz】,自己编译。
在CentOS下:

3.3.1 安装编译相关工具

yum -y groupinstall "Development tools"
yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel
yum install libffi-devel -y

3.3.2 解包和安装

假如刚才你已经下载了Python-3.10.1.tgz,那么:

tar -zxf Python-3.10.1.tgz -C ~
mkdir ~/python3
cd ~/Python-3.10.1
./configure --prefix=/home/你自己的用户名/python3
make && make install

然后等一会儿,看输出是完成还是失败。

3.3.3 用咱自己的版本

因为系统中还有其它版本的Python,需要指定用我们自己的版本。
我没有替换/usr/bin/里面的链接,考虑到其它用户还得用。
所以改自己用户的path。

vim ~/.bashrc
#加到path的前面
export PATH=/home/你自己的用户名/python3/bin:$PATH

(五)程序执行结果

因为前面setDeployMode("client"),所以driver程序是执行在Windows本机的(要不准备那么多环境干嘛)。
比较小的结果可以不放进HDFS,直接放本机,方便查看。

我自己测试是OK的,集群是Spark独立集群。
带**的日志就是被提交的应用日志,通过读重定向后的日志文件得到的。

测试提交Java应用执行中:
在这里插入图片描述
测试提交Python应用执行记录:
在这里插入图片描述

看看集群的应用记录:
在这里插入图片描述


OK,成功!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值