打包代码与依赖说明
在开发中,我们写的应用程序通常需要依赖第三方的库(即程序中引入了既不在 org.apache.spark包,也不再语言运行时的库的依赖),我们就需要确保所有的依赖在Spark应用运行时都能被找到
- 对于Python而言,安装第三方库的方法有很多种
- 可以通过包管理器(如pip)在集群中所有机器上安装所依赖的库,或者手动将依赖安装到python安装目录下的site-packages/目录在
- 我们也可以通过spark-submit 的 --py-Files 参数提交独立的库
- 如果我们没有在集群上安装包的权限,可以手动添加依赖库,但是要防范与已经安装在集群上的那些包发生冲突
注意:
提交应用时,绝不要把spark本身放在提交的依赖中。spark-submit会自动确保spark在你的程序的运行路径中
- 对于Java 和 Scala,可以通过spark-submit 的 --jars 标记提交独立的jar包依赖
- 当只有一两个库的简单依赖,并且这些库不依赖与其他库时,这种方式比较合适
- 当需要依赖很多库的使用,这种方式很笨拙,不太适用。
- 此时的常规做法时使用构建工具(如maven、sbt)生成一个比较大的jar包,这个jar包中包含应用的所有的传递依赖。
使用Maven构建Java编写的Spark Application
参考POM
<repositories>
<!-- 指定仓库的位置,依次为aliyun、cloudera、jboss -->
<repository>
<id>aliyun</id>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</repository>
<repository>
<id>cloudera</id>
<url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
</repository>
<repository>
<id>jboss</id>
<url>https://repository.jboss.com/nexus/content/groups/public/</url>
</repository>
</repositories>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<scala.version>2.12.15</scala.version>
<scala.binary.version>2.12</scala.binary.version>
<hadoop.version>3.1.3</hadoop.version>
<spark.version>3.2.0</spark.version>
<spark.scope>compile</spark.scope>
</properties>
<dependencies>
<!-- 依赖Scala语言-->
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>${scala.version}</version>
</dependency>
<!-- Spark Core 依赖 -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_${scala.binary.version}</artifactId>
<version>${spark.version}</version>
</dependency>
<!-- Hadoop Client 依赖 -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>${hadoop.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>${maven.compiler.source}</source><!-- 源代码使用的JDK版本 -->
<target>${maven.compiler.target}</target><!-- 需要生成的目标class文件的编译版本 -->
<encoding>${project.build.sourceEncoding}</encoding><!-- 字符集编码 -->
</configuration>
</plugin>
</plugins>
</build>
使用Maven构建Scala编写的Spark Application
参考POM
<repositories>
<!-- 指定仓库的位置,依次为aliyun、cloudera、jboss -->
<repository>
<id>aliyun</id>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</repository>
<repository>
<id>cloudera</id>
<url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
</repository>
<repository>
<id>jboss</id>
<url>https://repository.jboss.com/nexus/content/groups/public/</url>
</repository>
</repositories>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<scala.version>2.13.5</scala.version>
<scala.binary.version>2.13</scala.binary.version>
<spark.version>3.2.0</spark.version>
<hadoop.version>3.1.3</hadoop.version>
</properties>
<dependencies>
<!-- 依赖Scala语言-->
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>${scala.version}</version>
</dependency>
<!-- Spark Core 依赖 -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_${scala.binary.version}</artifactId>
<version>${spark.version}</version>
</dependency>
<!-- Hadoop Client 依赖 -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>${hadoop.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<!--maven的打包插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<!--该插件用于将scala代码编译成class文件-->
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.2.2</version>
<executions>
<!--绑定到maven的编译阶段-->
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
使用sbt构建Scala编写的Spark Application
目前未使用,暂时未记录
依赖冲突
当我们的Spark Application与Spark本身依赖于同一个库时可能会发生依赖冲突,导致程序崩溃。
依赖冲突通常表现为:
- NoSuchMethodError
- ClassNotFoundException
- 或其他与类加载相关的JVM异常
对于这类问题,主要的两种解决方式:
1)修改Spark Application,使其使用的依赖库版本与Spark所使用的相同
2)通常使用”shading“的方式打包我们的Spark Application