• Mapreduce部署与第三方依赖包管理


       Mapreduce部署是总会涉及到第三方包依赖问题,这些第三方包配置的方式不同,会对mapreduce的部署便捷性有一些影响,有时候还会导致脚本出错。本文介绍几种常用的配置方式:

    1. HADOOP_CLASSPATH

        在hadoop的相关配置文件中,添加CLASSPATH路径,那么在hadoop的各个进程启动时都会载入这些包,因此对于mapreduce-job jar中则不需要额外的引入这些jars,所以mapreduce-job jar会比较小[瘦jar],便于传输;但它的问题也比较明显,如果mapreduce-job中新增了其他引用jar,则必须重新启动hadoop的相关进程。

        我们可以在hadoop-env.sh中,增加如下配置:

    export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:/path/customer/jars

        其中“/path/customer/jars”路径为自己的第三方jar所在的本地路径,我们需要在集群中所有的hadoop机器上都同步这些jar。

        瘦jar的打包方式(maven):

    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-dependency-plugin</artifactId>
      <executions>
        <execution>
          <id>copy-dependencies</id>
          <phase>prepare-package</phase>
          <goals>
            <goal>copy-dependencies</goal>
          </goals>
          <configuration>
            <outputDirectory>${project.build.directory}/lib</outputDirectory>
            <overWriteReleases>false</overWriteReleases>
            <overWriteSnapshots>false</overWriteSnapshots>
            <overWriteIfNewer>true</overWriteIfNewer>
          </configuration>
        </execution>
      </executions>
    </plugin>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <configuration>
        <archive>
          <manifest>
            <addClasspath>true</addClasspath>
            <classpathPrefix>lib/</classpathPrefix>
            <mainClass>com.app.script.Main</mainClass>
          </manifest>
        </archive>
      </configuration>
    </plugin>

        使用了copy-dependencies插件,当使用“mvn package”命令打包之后,第三方引用包会被copy到打包目录下的lib文件中(并非mapreduce-job jar内部的lib文件中),开发者只需要把这些jars上传到所有hadoop集群即可。

    2. mapred.child.env

        我们可以指定mapreduce的task子进程启动时加载第三方jars,而不是让所有的hadoop子进程都加载。通过在mapred-site.xml中增加如下配置:

    <property>
        <name>mapred.child.env</name>
        <value>LD_LIBRARY_PATH=/path/customer/jars</value>
        <!-- 
          LD_LIBRARY_PATH=$HADOOP_HOME/mapred-lib/thirdparty
        -->
    </property>

        这种方式和1)类似,不过更加便捷,每个mapper或者reducer子进程启动时都会重新加载第三方jars,所以当jars有变动时,只需要直接覆盖它们即可,而无需重启hadoop或者yarn。

    3. -libjars选项

        我们可以在使用“hadoo jar”命令时,向启动的job传递“libjars”选项参数,同时配合ToolRunner工具来解析参数并运行Job,这种方式是推荐的用法之一,因为它可以简单的实现job的依赖包和hadoop classpath解耦,可以为每个job单独设置libjars参数。这些jars将会在job提交之后复制到hadoop“共享文件系统中”(hdfs,/tmp文件夹中),此后taskTracker即可load到本地并在任务子进程中加载。

        libjars中需要指定job依赖的所有的jar全路径,并且这些jars必须在当前本地文件系统中(并非集群中都需要有此jars),暂时还不支持hdfs。对于在HADOOP_CLASSPATH或者mapred.child.env中已经包含了jars,则不需要再-libjars参数中再次指定。因为libjars需要指定jar的全路径名,所以如果jars特别多的话,操作起来非常不便,所以我们通常将多个job共用的jars通过HADOOP_CLASSPATH或者mapred.child.end方式配置,将某个job依赖的额外的jars(少量的)通过-libjars选项指定。

    hadoop jar statistic-mr.jar com.statistic.script.Main -libjars /path/cascading-core-2.5.jar,/path/cascading-hadoop-2.5.jar

    4. Fatjar

        胖jar,即将mapreduce-job jar所依赖的所有jar都“shade”到一个jar中,最终package成一个“独立”的可运行的jar;当然hadoop并不需要这个jar是“可运行的”,它只需要这个jar在运行时不需要额外的配置“--classpath”即可。此外Fatjar仍然可以使用HADOOP_CLASSPATH或者map.child.env所加载的jars,因为我们在打包时可以将这些jars排除,以减少fatjar的大小。

        fatjar只不过是一种打包的方式,也仍然可以和“-libjars”选项配合。不过从直观上来说,fatjar确实是解决“-libjars”不方便的技巧。

        此例中,我们使用cascading来开发一个mapreduce job,但是我们又不希望cascading的相关依赖包被放入HADOOP_CLASSPATH中,因为其他的job可能不需要或者其他的job有可能使用其他版本的cascading;所以就使用Fatjar,把job程序和cascading的依赖包全部“shade”在一起。

        使用maven assambly插件来完成fatjar的打包工作:

        1) pom.xml

    <build>
      <finalName>statistic-mapred</finalName>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-assembly-plugin</artifactId>
          <configuration>
            <descriptors>
              <descriptor>src/assembly.xml</descriptor>
            </descriptors>
            <archive>
              <!-- optional -->
              <!--
              <manifest>
                <mainClass>com.script.Main</mainClass>
                <addClasspath>true</addClasspath>
              </manifest>
              -->
            </archive>
          </configuration>
          <executions>
            <execution>
              <id>make-assembly</id>
              <phase>package</phase>
              <goals>
                <goal>single</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>

        2) assambly.xml

    <assembly>
      <id>cascading</id>
      <formats>
        <format>jar</format>
      </formats>
      <includeBaseDirectory>false</includeBaseDirectory>
      <dependencySets>
        <dependencySet>
          <unpack>true</unpack>
          <scope>runtime</scope>
          <!--
          <excludes>
            <exclude>org.apache.hadoop:*</exclude>
          </excludes>
          -->
          <!-- very small jar -->
          <includes>
            <include>cascading:*</include>
            <include>thirdparty:*</include>
          </includes>
        </dependencySet>
      </dependencySets>
      <fileSets>
        <fileSet>
          <directory>${project.build.outputDirectory}</directory>
          <outputDirectory>/</outputDirectory>
        </fileSet>
      </fileSets>
    </assembly>

       在assambly.xml中我们通过<include>标签来包含需要被“shade”的第三方依赖包,并且采用了unpack(解压)方式,此例中我们只将cascading的jar打进fatjar中,对于其他包将会被忽略,因为这些包已经在hadoop中存在(比如hadoop,hdfs,mapreduce,已经其他的常用包,都可以共用hadoop的),最终我们的打包结果如下:



     

        有了fatjar,确实大大的减少了开发工程师部署mapreduce的复杂度和出错的可能性,如果你有即备的maven环境,建议使用fatjar的方式。将fatjar直接放在hadoop中使用“hadoop jar”指令即可执行,几乎无需关心依赖包遗漏的问题。

        此外,需要备注一下,在使用cascading时,如果采用了HADOOP_CLASSPATH或者mapred.child.env方式管理依赖时,会偶尔抛出:

    Split class cascading.tap.hadoop.MultiInputSplit not found

        尽管cascading的所有依赖包都在CLASSPATH中,也无法解决这个问题,不确定究竟发生了什么!!后来采用了fatjar之后,问题解决!!

  • 相关阅读:
    spring cloud-zuul的Filter详解
    Hibernate day01
    JAVA中几种常用的RPC框架介绍
    乐观锁和悲观锁的区别(最全面的分析)
    Redis、Memcache和MongoDB的区别
    Hessian整合Spring
    Hessian的使用以及理解
    sso单点登录系统原理与实现
    zookeeper原理(转)
    Nginx的负载均衡的几种方式
  • 原文地址:https://www.cnblogs.com/sha0830/p/5062169.html
Copyright © 2020-2023  润新知