(一)代码提交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
- Install a full native windows Hadoop version. The ASF does not currently (September 2015) release such a version; releases are available externally.
- Or: get the WINUTILS.EXE binary from a Hadoop redistribution. There is a repository of this for some Hadoop versions on github.
Then
- Set the environment variable %HADOOP_HOME% to point to the directory above the BIN dir containing WINUTILS.EXE.
- 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.exe 为 python3.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,成功!