大數據應用經常使用打包方式

1、簡介

在提交大數據做業到集羣上運行時,一般須要先將項目打成 JAR 包。這裏以 Maven 爲例,經常使用打包方式以下:git

  • 不加任何插件,直接使用 mvn package 打包;
  • 使用 maven-assembly-plugin 插件;
  • 使用 maven-shade-plugin 插件;
  • 使用 maven-jar-plugin 和 maven-dependency-plugin 插件;

如下分別進行詳細的說明。github

2、mvn package

不在 POM 中配置任何插件,直接使用 mvn package 進行項目打包,這對於沒有使用外部依賴包的項目是可行的。但若是項目中使用了第三方 JAR 包,就會出現問題,由於 mvn package 打的 JAR 包中是不含有依賴包,會致使做業運行時出現找不到第三方依賴的異常。這種方式侷限性比較大,由於實際的項目每每很複雜,一般都會依賴第三方 JAR。shell

大數據框架的開發者也考慮到這個問題,因此基本全部的框架都支持在提交做業時使用 --jars 指定第三方依賴包,可是這種方式的問題一樣很明顯,就是你必須保持生產環境與開發環境中的全部 JAR 包版本一致,這是有維護成本的。apache

基於上面這些緣由,最簡單的是採用 All In One 的打包方式,把全部依賴都打包到一個 JAR 文件中,此時對環境的依賴性最小。要實現這個目的,可使用 Maven 提供的 maven-assembly-pluginmaven-shade-plugin 插件。編程

3、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(名稱可自定義),並指定做業的主入口類:app

<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 進行打包時命令以下:maven

# mvn assembly:assembly

打包後會同時生成兩個 JAR 包,其中後綴爲 jar-with-dependencies 是含有第三方依賴的 JAR 包,後綴是由 assembly.xml<id> 標籤指定的,能夠自定義修改。ide

4、maven-shade-plugin插件

maven-shade-pluginmaven-assembly-plugin 功能更爲強大,好比你的工程依賴不少的 JAR 包,而被依賴的 JAR 又會依賴其餘的 JAR 包,這樣,當工程中依賴到不一樣的版本的 JAR 時,而且 JAR 中具備相同名稱的資源文件時,shade 插件會嘗試將全部資源文件打包在一塊兒時,而不是和 assembly 同樣執行覆蓋操做。

一般使用 maven-shade-plugin 就可以完成大多數的打包需求,其配置簡單且適用性最廣,所以建議優先使用此方式。

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。

5、其餘打包需求

1. 使用非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>

2. 排除集羣中已經存在的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> 進行排除。

3. 打包Scala文件

若是你使用到 Scala 語言進行編程,此時須要特別注意 :默認狀況下 Maven 是不會把 scala 文件打入最終的 JAR 中,須要額外添加 maven-scala-plugin 插件,經常使用配置以下:

<plugin>
    <groupId>org.scala-tools</groupId>
    <artifactId>maven-scala-plugin</artifactId>
    <version>2.15.1</version>
    <executions>
        <execution>
            <id>scala-compile</id>
            <goals>
                <goal>compile</goal>
            </goals>
            <configuration>
                <includes>
                    <include>**/*.scala</include>
                </includes>
            </configuration>
        </execution>
        <execution>
            <id>scala-test-compile</id>
            <goals>
                <goal>testCompile</goal>
            </goals>
        </execution>
    </executions>
</plugin>

參考資料

關於 Maven 各個插件的詳細配置能夠查看其官方文檔:

關於 maven-shade-plugin 的更多配置也能夠參考該博客: maven-shade-plugin 入門指南

更多大數據系列文章能夠參見 GitHub 開源項目大數據入門指南

相關文章
相關標籤/搜索