hadoop系列文档5-对官方MapReduce 过程的翻译(一)

MapReduce教程

 

MapReduce教程

 

 

目的

本文全面描述了所有面向用户方面Hadoop mapReduce框架和服务作为一个教程。

环境条件

确保Hadoop被安装、配合、并且运行。 更多:

总览

Hadoop MapReduce 是一个方便应用在集群(上千节点)同时并行处理大量数据(TB级别的数据源)并具有可靠、容灾性的软件框架。

一个MapReduce任务通常把输入数据分割成独立的数据块并有map tasks并行处理。框架分类输出maps,然后这些maps被传至reduce tasks。通常任务的输入和输出都存在一个文件系统中。框架负责计划、监控这些任务,并且重新执行失败的任务。

一般来说,运行和存储数据是在相同的节点上,换句话说,MapReduce框架和Hadoop分布式文件系统是运行在相同的节点上的。这样配置能有效解决因集群传输数据产生的带宽压力。

MapReduce框架包含单一主要的ResourceManager,一个NodeManager 在每个集群中,在每个应用中包含一个MRAppMaster 。

一个job的最低配置包含,输入输出路径,map和reduce类,以及其他别的一些配置。

Hadoop job客户端配置提交任务给ResourceManager ,ResourceManager 负责把配置和程序分发给各个节点,计划、监控任务,并且提供运行状态返回给客户端诊断信息。

虽然Hadoop框架是由JAVA实现的,但是MapReduce任务并不一定需要由JAVA编写。

  • Hadoop Streaming is a utility which allows users to create and run jobs with any executables (e.g. shell utilities) as the mapper and/or the reducer.
  • Hadoop Pipes is a SWIG-compatible C++ API to implement MapReduce applications (non JNI™ based).

输入输出

MapReduce框架以<key,value>的形式处理输入和输出数据。

Key和Value必须又框架序列化。因此需要实现 Writable接口。此外key 类还必须实现WritableComparable 来促进框架分类。

Input and Output types of a MapReduce job:

(input) <k1, v1>-> map -><k2, v2> -> combine -> <k2, v2> -> reduce -><k3, v3> (output)

Example: WordCountv1.0

在深入认识之前,先通过一个简单的MapRecude例子来了解它们是如何通过的。

WordCount 程序通过给定的输入数据计算其中每个出现单词的频数。

适用于单机模式、伪分布式、完全分布式模式。 (Single Node Setup).

源码

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;
importorg.apache.hadoop.mapreduce.lib.input.FileInputFormat;
importorg.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
 
public class WordCount {
 
  public staticclass TokenizerMapper
       extendsMapper<Object, Text, Text, IntWritable>{
 
    private finalstatic IntWritable one = new IntWritable(1);
    private Textword = new Text();
 
    public voidmap(Object key, Text value, Context context
                   ) throws IOException, InterruptedException {
     StringTokenizer itr = new StringTokenizer(value.toString());
      while(itr.hasMoreTokens()) {
       word.set(itr.nextToken());
       context.write(word, one);
      }
    }
  }
 
  public staticclass IntSumReducer
       extends Reducer<Text,IntWritable,Text,IntWritable>{
    privateIntWritable result = new IntWritable();
 
    public voidreduce(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 staticvoid main(String[] args) throws Exception {
    Configurationconf = new Configuration();
    Job job =Job.getInstance(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);
   FileInputFormat.addInputPath(job, new Path(args[0]));
   FileOutputFormat.setOutputPath(job, new Path(args[1]));
   System.exit(job.waitForCompletion(true) ? 0 : 1);
  }
}

用法

确保如下环境变量:

export JAVA_HOME=/usr/java/default
export PATH=${JAVA_HOME}/bin:${PATH}
export HADOOP_CLASSPATH=${JAVA_HOME}/lib/tools.jar
Compile WordCount.java and create a jar:
$ bin/hadoop com.sun.tools.javac.Main WordCount.java
$ jar cf wc.jar WordCount*.class
Assuming that:
/user/joe/wordcount/input - input directory in HDFS
/user/joe/wordcount/output - output directory in HDFS
Sample text-filesas input:
$ bin/hadoop fs -ls /user/joe/wordcount/input/ /user/joe/wordcount/input/file01/user/joe/wordcount/input/file02
 
$ bin/hadoop fs -cat /user/joe/wordcount/input/file01
Hello World Bye World
 
$ bin/hadoop fs -cat /user/joe/wordcount/input/file02
Hello Hadoop Goodbye Hadoop
Run theapplication:
$ bin/hadoop jar wc.jar WordCount/user/joe/wordcount/input /user/joe/wordcount/output
Output:
$ bin/hadoop fs -cat/user/joe/wordcount/output/part-r-00000`
Bye 1
Goodbye 1
Hadoop 2
Hello 2
World 2`

你可以通过 –files选项来使应用根据空格分割路径使其存储在当前路径下。

你还可以通过 –libjars选项来添加jars。

-archives选项能够允许根据空格分割来传递参数,使其作为变量。

更多细节可以参考Commands Guide.

Running wordcount example with -libjars, -files and -archives:

bin/hadoop jar hadoop-mapreduce-examples-<ver>.jarwordcount -files cachefile.txt -libjars mylib.jar -archives myarchive.zip inputoutput

这里的myarchive.zip需要放置并且解压缩。

用户可以为files和archives指定不同的名字,通过使用#符号。

For example,

bin/hadoop jar hadoop-mapreduce-examples-<ver>.jarwordcount -files dir1/dict.txt#dict1,dir2/dict.txt#dict2 -archivesmytar.tgz#tgzdir input output

Walk-through

The WordCount application is quitestraight-forward.
public void map(Object key, Text value, Context context
                )throws IOException, InterruptedException {
  StringTokenizeritr = new StringTokenizer(value.toString());
  while(itr.hasMoreTokens()) {
   word.set(itr.nextToken());
   context.write(word, one);
  }
}


Mapper 通过map方法来实现,每一行记录运行一次,格式是特殊指定的TextInputFormat,

靠空格来分割行,通过StringTokenizer类,并且传递键值对,比如< <word>, 1>.

给定的输入,经过第一个map处理,输出如下:

< Hello, 1>
< World, 1>
< Bye, 1>
< World, 1>


经过第二个map处理,输出如下:

< Hello, 1>
< Hadoop, 1>
< Goodbye, 1>
< Hadoop, 1>


我们将下接下来的教程中学习更多关于给定任务的map数量,并且如何控制这些map的数量。

   job.setCombinerClass(IntSumReducer.class);

WordCount程序里面每个map都会进行根据key来聚合。

The output of the firstmap:

< Bye, 1>
< Hello, 1>
< World, 2>`


The output of thesecond map:

< Goodbye, 1>
< Hadoop, 2>
< Hello, 1>`


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


The Reducer implementation, via the reduce method just sums up the values,which are the occurence counts for each key (i.e. words in this example).

Thus the output ofthe job is:

< Bye, 1>
< Goodbye, 1>
< Hadoop, 2>
< Hello, 2>
< World, 2>`

Main方法指定各种参数,比如输入,输出路径(通过命令),键值对类型,输入输出格式。在任务重,会调用job.waitForCompletion来确认任务和监控进程。

MapReduce –用户接口

首先来看看Mapper和Reducer接口,应用通过实现他们来提供map和reduce方法。

然后再来讨论别的接口,暴扣 Job, Partitioner, InputFormat, OutputFormat, and others.

最后,再来讨论框架的一些有用的特性,包括DistributedCache, IsolationRunner等

Payload

Applicationstypically implement the Mapper and Reducer interfaces to provide the map and reduce methods. These form the core of thejob.

Mapper

Mapper 使输入的键值对变成中间(处理过的)键值对。

Maps使用单独的Tasks来转化输入的记录变成中间(临时)记录,转化并不需要和输入记录一个格式,而且1个键值对可以被转化成0个或多个键值对。

Hadoop MapReduce框架通过InputSplit 来分每个map,并通过InputFormat 来生成。

总得来说,Mapper通过Job.setMapperClass(Class) 方法来实现任务。框架会为task 在InputSplit 调用map(WritableComparable, Writable,Context) 来处理每个键值对。应用重写cleanup方法去执行任何需要的cleanup。

输出的键值对也不需要和输入的键值对相同,可以是0个也可以是多个。通过调用context.write(WritableComparable, Writable)来搜集。

应用可以使用计数器来统计。

所有中间值都被框架分组,并经过Reduces,决定最后的输出,用户可以通过设置Job.setGroupingComparatorClass(Class).来控制分组Comparator 。

the  Mapper的输出被分组并被分配给每个Reducer。分组的数量和reduce tasks数量一致。用户可以通过实现Partitioner来控制那些key去到哪些Reducer.

用户通过设置 Job.setCombinerClass(Class)来帮助切割从Mapper to the Reducer.传输的数据大小

中间结果通常是简答的(key-len, key, value-len, value)格式,程序可以通过 CompressionCodec设置控制这些中间的数据是否以及以什么方式压缩

How Many Maps?

通常来说,maps的数量由输入文件的大小所决定,或者说是输入文件的块的数量。

推荐的并行maps的数量每节点大概在10-100个,在低cpu占用的可以设置到300个。Task的设置需要一些时间,所以最好最少花费1分钟的时间去执行。

所以,如果你有10TB的数据,然后设置的数据块的大小是128MB,那么你将会有82000个maps。除非你自己通过Configuration.set(MRJobConfig.NUM_MAPS, int)来设置maps到更多得数量。

Reducer

Reducer通过公共key来减少中间数据的量。

可以通过Job.setNumReduceTasks(int)来设置任务的数量。

Overall, Reducer implementations are passed the Job for the job via the Job.setReducerClass(Class) method and canoverride it to initialize themselves. The framework then calls reduce(WritableComparable, Iterable<Writable>,Context) method for each <key, (list of values)> pair in thegrouped inputs. Applications can then override the cleanup(Context) method toperform any required cleanup.

Reducer 有3个主要的阶段,shuffle, sort and reduce.

Shuffle

Reducer 的输入,是经过分类的mappers的输出。在这个阶段,框架通过Http取得所有mappers输出的相关分区。

Sort

在这个阶段,框架分组通过key来分来所有的输入(因此不同的mapper可能会输出相同的key)。

Shuffle和sort阶段是一起发生的。所以map-outputs得到的是他们融合后的结果。

Secondary Sort

在reduction之前的分组规则,如果是有必须和中间数据的分组规则不一样的话,那么一种可以通过

Job.setSortComparatorClass(Class).来指定以个Comparator ,Job.setGroupingComparatorClass(Class)可以用来指定如何控制中间数据的分割。

这些可以在用在模拟第二次排序。

Reduce
在这个阶段,reduce(WritableComparable, Iterable<Writable>, Context)方法被每个 <key, (list ofvalues)> 调用。

reduce task输出通过Context.write(WritableComparable,Writable)被写进 FileSystem

应用程序可以使用计数器来统计。

Reducer 的输出没有被排序。

How Many Reduces?

正确的reduces的数量似乎介于0.95或者1.75乘以(节点的数量,每个节点最大容器的数量)

0.95的话,所有的reduces能在map完成的时候立即运行并开始转换map的输出。1.75的话,不仅完成第一轮的reduces,并且会运行第二轮的reduces来确保job的负载。

当Reduce任务的数量是任务槽0.95倍的时候,如何一个Reduce任务失败,Hadoop可以很快地找到一台空闲的机器重新执行这个任务。当Reduce任务的数量是任务槽的1.75倍时,执行速度快的机器可以获得更多的Reduce任务,因此使负载更加均衡,以提高任务的处理速度。

增加reduces的数量会额外增加框架的开销,但是增加负载会减少故障率。

The scaling factors above are slightly less than whole numbers to reservea few reduce slots in the framework for speculative-tasks and failed tasks.

Reducer NONE

如果没有得到reduction,那么设置reduce-tasks成0是合法的。

在这种情况下,map-tasks的输出,直接到文件系统,通过FileOutputFormat.setOutputPath(Job, Path).设置输出路径。在把他们写入文件系统之前,框架不对map-outputs进行排序。

Partitioner

Partitioner partitions the key space.

Partitioner controls the partitioning of the keys of the intermediatemap-outputs. The key (or a subset of the key) is used to derive the partition,typically by a hash function. The total number of partitions is thesame as the number of reduce tasks for the job. Hence this controls which ofthe m reduce tasks the intermediate key (and hence the record) is sent tofor reduction.

HashPartitioner is the default Partitioner.

Counter

Counter is a facility for MapReduceapplications to report its statistics.

Mapper and Reducer implementationscan use the Counter to report statistics.

Hadoop MapReduce comes bundled with a library of generally useful mappers,reducers, and partitioners.


猜你喜欢

转载自blog.csdn.net/u010237107/article/details/50865669
今日推荐