BigData-Notes/notes/大数据应用常用打包方式.md
2019-05-20 23:34:45 +08:00

9.8 KiB
Raw Blame History

大数据应用常用打包方式

一、简介

在提交大数据作业到集群中运行时通常都需要先将项目打成Jar包。Java项目通常都采用Maven进行构建常用的打包方式有以下三种

  • 第一种不加任何插件直接使用mvn package打包
  • 第二种使用maven-assembly-plugin插件进行打包
  • 第三种使用maven-shade-plugin插件进行打包。

以下分别进行详细的说明。

二、mvn package

不在POM中配置任何插件直接使用mvn package进行项目打包这对于没有使用外部依赖包的项目是可行的。但如果项目中使用了第三方JAR包就会出现问题因为mvn package打的Jar包中是不含有依赖包会导致作业运行时出现找不到第三方依赖的异常。这种方式局限性比较大因为实际的项目往往很复杂通常都会依赖第三方Jar。

大数据框架的开发者也考虑到这个问题,所以基本所有的框架都支持在提交作业时使用--jars指定第三方依赖包但是这种方式的问题同样很明显就是你必须保持生产环境与开发环境中的所有Jar包版本一致这是有维护成本的。

基于上面这些原因,最简单的是采用All In One的打包方式把所有依赖都打包到一个Jar文件中此时对环境的依赖性最小。要实现这个目的可以使用Maven提供的maven-assembly-pluginmaven-shade-plugin插件。

三、maven-assembly-plugin插件

Assembly插件支持将项目的所有依赖、文件都打包到同一个输出文件中。目前支持输出以下文件类型:

  • zip
  • tar
  • tar.gz (or tgz)
  • tar.bz2 (or tbz2)
  • tar.snappy
  • tar.xz (or txz)
  • jar
  • dir
  • war

3.1 基本使用

在POM.xml中引入插件指定打包格式的配置文件assembly.xml(名称可自定义),并指定作业的主入口类。

<build>
    <plugins>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <descriptors>
                    <descriptor>src/main/resources/assembly.xml</descriptor>
                </descriptors>
                <archive>
                    <manifest>
                        <mainClass>com.heibaiying.wordcount.ClusterWordCountApp</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

assembly.xml文件内容如下

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 
                              http://maven.apache.org/xsd/assembly-2.0.0.xsd">
    
    <id>jar-with-dependencies</id>

    <!--指明打包方式-->
    <formats>
        <format>jar</format>
    </formats>

    <includeBaseDirectory>false</includeBaseDirectory>
    <dependencySets>
        <dependencySet>
            <outputDirectory>/</outputDirectory>
            <useProjectArtifact>true</useProjectArtifact>
            <unpack>true</unpack>
            <scope>runtime</scope>
            <!--这里以排除storm环境中已经提供的storm-core为例演示排除Jar包-->
            <excludes>
                <exclude>org.apache.storm:storm-core</exclude>
            </excludes>
        </dependencySet>
    </dependencySets>
</assembly>

3.2 打包命令

采用maven-assembly-plugin进行打包时命令如下

# mvn assembly:assembly 

打包后会同时生成两个JAR包其中后缀为jar-with-dependencies是含有第三方依赖的JAR包后缀是由assembly.xml<id>标签指定的,可以自定义修改。

四、maven-shade-plugin插件

maven-shade-pluginmaven-assembly-plugin功能更丰富比如你的工程依赖很多的JAR包而被依赖的JAR又会依赖其他的JAR包这样,当工程中依赖到不同的版本的 JAR时并且JAR中具有相同名称的资源文件时shade插件会尝试将所有资源文件打包在一起时而不是和assembly一样执行覆盖操作。

4.1 基本配置

采用maven-shade-plugin进行打包时候,配置示例如下:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <configuration>
        <createDependencyReducedPom>true</createDependencyReducedPom>
        <filters>
            <filter>
                <artifact>*:*</artifact>
                <excludes>
                    <exclude>META-INF/*.SF</exclude>
                    <exclude>META-INF/*.sf</exclude>
                    <exclude>META-INF/*.DSA</exclude>
                    <exclude>META-INF/*.dsa</exclude>
                    <exclude>META-INF/*.RSA</exclude>
                    <exclude>META-INF/*.rsa</exclude>
                    <exclude>META-INF/*.EC</exclude>
                    <exclude>META-INF/*.ec</exclude>
                    <exclude>META-INF/MSFTSIG.SF</exclude>
                    <exclude>META-INF/MSFTSIG.RSA</exclude>
                </excludes>
            </filter>
        </filters>
        <artifactSet>
            <excludes>
                <exclude>org.apache.storm:storm-core</exclude>
            </excludes>
        </artifactSet>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <transformer
                       implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                    <transformer
                       implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

以上配置来源于Storm的Github仓库在上面的配置中排除了部分文件这是因为有些JAR包生成时会使用jarsigner生成文件签名(完成性校验)分为两个文件存放在META-INF目录下

  • a signature file, with a .SF extension
  • a signature block file, with a .DSA, .RSA, or .EC extension

如果某些包的存在重复引用,这可能会导致在打包时候出现Invalid signature file digest for Manifest main attributes异常,所以在配置中排除这些文件。

4.2 打包命令

使用maven-shade-plugin进行打包的时候打包命令和普通打包一样

# mvn package

打包后会生成两个JAR包提交到服务器集群时使用非original开头的Jar。

五、使用非Maven仓库中的Jar

通常上面两种打包能够满足大多数的使用场景。但是如果你想把某些没有被Maven管理Jar包打入到最终的Jar中比如你在resources/lib下引入的其他非Maven仓库中的Jar此时可以使用maven-jar-pluginmaven-dependency-plugin插件将其打入最终的Jar中。

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                          <!--指定resources/lib目录-->
                        <classpathPrefix>lib/</classpathPrefix>
                          <!--应用的主入口类-->
                        <mainClass>com.heibaiying.BigDataApp</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy</id>
                    <phase>compile</phase>
                    <goals>
                         <!--将resources/lib目录所有Jar包打进最终的依赖中-->
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                         <!--将resources/lib目录所有Jar包一并拷贝到输出目录的lib目录下-->
                        <outputDirectory>
                            ${project.build.directory}/lib
                        </outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

六、排除集群中已经存在的Jar

为了避免冲突通常官方文档通常都会建议你排除集群中已经提供的Jar包如下

Spark 官方文档 Submitting Applications 章节:

When creating assembly jars, list Spark and Hadoop as provided dependencies; these need not be bundled since they are provided by the cluster manager at runtime.

Strom官方文档 Running Topologies on a Production Cluster 章节:

Then run mvn assembly:assembly to get an appropriately packaged jar. Make sure you exclude the Storm jars since the cluster already has Storm on the classpath.

  • 对需要排除的Jar包依赖添加<scope>provided</scope>标签此时该Jar包会被排除但是不建议使用这种方式因为此时你在本地运行也无法使用该Jar包
  • 建议直接在maven-assembly-pluginmaven-shade-plugin的配置文件中使用<exclude>进行排除。

七、使用建议

通常使用maven-shade-plugin就能够完成大多数的打包需求,其配置简单且适用性最广,因此建议使用此方式。