Hadoop应用引用第三方jar的几种方式

 

简单来说,Hadoop引入第三方jar包有以下几种方式:

    • 一、把引用到的所有的第三方jar包打到一个jar包内,形成一个超大包,像上一篇文章中提到的第二种引入jar之后打包的方式;
    • 二、把引用到的所有的第三方jar包放到Hadoop的lib目录下,需要Hadoop集群中的每个节点都要放;
    • 三、把jar包放在集群中固定的一台机器上,使用libjars命令加载第三方jar;
    • 四、把jar包放在HDFS上,动态加载第三方jar包。

 

接下来对这几种方式的优缺点,说一下我个人的见解:

 

一、把引用到的所有的第三方jar包打到一个jar包内

优点:在hadoop集群上可以直接运行,运行命令也是比较简单;

缺点:把所以的jar包放在一起,文件过大,考虑到加入升级版本的话,引用的第三方jar文件一般不会发生变化,这种打包方式每次都要把第三方jar文件打包在一起上传。

这种打包方式在上一篇文章中《Hadoop应用引用第三方jar的几种方式(一)》已经进行了演示和说明,个人不太建议这种方式。

 

二、把引用到的所有的第三方jar包放到Hadoop的lib目录下

优点:在hadoop集群上可以直接运行,运行命令也是比较简单;

缺点:集群中的每个节点下都需要放置第三方jar,缺一不可,不够灵活,当版本升级的时候,需要对每一台机器上的jar包进行维护,不太容易进行维护。

对于这种方式,我没有进行实验,理论上来说是可行的,个人不太建议这种方式。

 

三、把jar包放在集群中固定的一台机器上,使用libjars命令加载第三方jar

优点:只需要维护hadoop集群中的一台机器上的lib库,易于系统的维护;

缺点:只能在存放jar的机器上去执行hadoop jar 命令执行程序,且执行命令较复杂;

个人对这种方式还可以接受,不过并不是我最喜欢的方式。

在这里,我进行了测试,WordCount的代码不变,打成WordCount_libjarscmd.jar,注意在打包的过程中不要选择lib中的jar文件,然后把OperateHDFS.jar放到集群中的一台机器上面,执行的命令如下所示:

hadoop jar WordCount_libjarscmd.jar com.hadoop.examples.WordCount -libjars OperateHDFS.jar input libjarscmdoutput

该命令的格式如下:

hadoop jar 要执行的jar 要执行的Class -libjars 第三方jar的目录 最后是程序要求的输入输出参数

程序的执行结果是ok,可以执行,没有问题,结果如下所示:

wKioL1UVD0zCdU2BAATLuihir4I782.jpg

 

四、把jar包放在HDFS上,动态加载第三方jar包

优点:程序可以方便的在集群上的任何一个节点运行,且执行命令的机器没有限制;

缺点:需要在程序中编写代码添加第三方jar,如果存放lib的目录发生了变化,那就只能改代码了。。。。

个人比较喜欢这种方式,毕竟存放lib的目录一般不会发生变化,我是这么认为的,(*^__^*) 嘻嘻……

 

    在这里,我对这种方式进行了测试,需要先把OperateHDFS.jar存放在HDFS上面,然后对WordCount稍作修改,增加动态的添加第三方jar的代码块,然后打成jar包WordCount_dynamicload.jar,注意在打包的过程中不要选择lib中的jar文件,执行的命令如下所示:

hadoop jar WordCount_dynamicload.jar com.hadoop.examples.WordCount input dynamicload

    程序的执行结果是ok,可以执行,没有问题,结果如下所示:

wKioL1UVFAaiYb8mAAR8eRvwxGk304.jpg

下面把WordCount源代码贴出来:

package com.hadoop.examples;
import java.io.IOException;
import java.util.StringTokenizer;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;

import com.hadoop.hdfs.OperateHDFS;

public class WordCount {

    public static class TokenizerMapper extends
            Mapper<Object, Text, Text, IntWritable> {

        private final static IntWritable one = new IntWritable(1);

        private Text word = new Text();

        public void map(Object key, Text value, Context context)
                throws IOException, InterruptedException {
            
            //它什么都不做,就是为了测试引入第三方jar的,如果找不到,肯定就会报ClassNotFound异常
            OperateHDFS s = new OperateHDFS();
            
            StringTokenizer itr = new StringTokenizer(value.toString());
            while (itr.hasMoreTokens()) {
                word.set(itr.nextToken());
                context.write(word, one);
            }
        }
    }

    public static class IntSumReducer extends
            Reducer<Text, IntWritable, Text, IntWritable> {

        private IntWritable result = new IntWritable();

        public void reduce(Text key, Iterable<IntWritable> values,
                Context context) throws IOException, InterruptedException {
            int sum = 0;
            for (IntWritable val : values) {
                sum += val.get();
            }
            result.set(sum);
            context.write(key, result);
        }
    }

    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        
        String[] otherArgs =
                new GenericOptionsParser(conf, args).getRemainingArgs();
        if (otherArgs.length < 2) {
            System.err.println("Usage: wordcount <in> [<in>...] <out>");
            System.exit(2);
        }
        Job job = new Job(conf, "word count");
        job.setJarByClass(WordCount.class);
        job.setMapperClass(TokenizerMapper.class);
        job.setCombinerClass(IntSumReducer.class);
        job.setReducerClass(IntSumReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
        
        /**
         * 其实我是做过测试的,把这个目录写成本地目录也可以的,
         * 就是第三种方式,不使用libjars命令加载,而是采用程序动态加载
         * 但是这样的话,就只能在固定的机器上执行命令,运行程序了,和第三种方式一样
         */
        //只有做第四种方式的时候,才需要把它打开,前三种方式,需要把它注释掉
        //job.addFileToClassPath(new Path("hdfs://192.168.3.57:8020/user/lxy/lib/OperateHDFS.jar"));
        for (int i = 0; i < otherArgs.length - 1; ++i) {
            FileInputFormat.addInputPath(job, new Path(otherArgs[i]));
        }
        FileOutputFormat.setOutputPath(job, new Path(
                otherArgs[otherArgs.length - 1]));
        System.exit(job.waitForCompletion(true) ? 0 : 1); 
    }
}

 

本文出自 “艾斯的梦想” 博客,请务必保留此出处http://acesdream.blog.51cto.com/10029622/1625688

4 thoughts on “Hadoop应用引用第三方jar的几种方式

  1. Does your site have a contact page? I’m having a tough time locating it
    but, I’d like to shoot you an e-mail. I’ve got some recommendations for your blog you might be interested in hearing.
    Either way, great site and I look forward to seeing
    it improve over time.

  2. It is perfect time to make a few plans for the longer term
    and it’s time to be happy. I’ve read this submit and if I may just I
    wish to suggest you some attention-grabbing things or tips.
    Maybe you can write subsequent articles referring to this article.
    I desire to read even more things about it!

Leave a Reply

Your email address will not be published. Required fields are marked *