HADOOP的部署及使用:二、Hadoop-MapReduce分布式计算模型

一、MapReduce分布式计算模型

 MapReduce分布式计算模型分为Map任务和Reduce任务两部分,为方便理解,将Map任务的输入标记为<k1,v1>,输出标记为<k2,v2>,Reduce任务的输出标记为<k3,v3>

Map任务执行计划

(1) 读取HDFS文件,通过InputFromat将文件分割为inputSplit,将每一行解析为一个<k1,v1>键值对,启动Map任务,对每个<k1,v1>调用一次map函数。

(2)覆盖map(),接受第一步产生的<k1,v1>,进行处理,转化为新的<k2,v2>输出,存储在本地磁盘。

(3)对(1)、(2)两部输出的<k1,v1>进行分区,默认分为一个区。

(4)对不同分区中的数据进行排序、分组。

(5)对分组后的数据进行合并(combine可选)

 

Reduce执行计划

(1)多个map任务的输出,按照不同的分区,通过网络copy到不同的reduce节点上(shuffle)

(2)对多个map的输出进行合并、排序。

(3)对reduce输出的<k3,v3>写到HDFS中。

 

如果把MapReduce细分,可以分为一下几大过程
Input-Split(输入分片):此过程是将从HDFS上读取的文件分片,然后送给Map端。有多少分片就有多少Mapper,一般分片的大小和HDFS中的块大小一致。
Shuffle-Spill(溢写):每个Map任务都有一个环形缓冲区,在默认情况下,缓冲区的大小为100MB,可以调整。一旦缓冲区达到阈值80%,一个后台线程便开始把内容“溢写”-“spill”到磁盘。在溢写过程中,map将继续输出到剩余的20%空间中,互不影响,如果缓冲区被填满map会被堵塞直到写磁盘完成。(在写磁盘之前会经历分区,排序,分组等过程)
Shuffle-Partition(分区):由于每个Map可能处理的数据量不同,所以到达reduce有可能会导致数据倾斜。分区可以帮助我们解决这一问题,在shuffle过程中会按照默认key的哈希码对分区数量取余,reduce便根据分区号来拉取对应的数据,达到数据均衡。分区数量对应Reduce个数。
Shuffle-Sort(排序):在分区后,会对此分区的数据进行内排序,排序过程会穿插在整个MapReduce中,在很多地方都存在。
Shuffle-Group(分组):分组过程会把key相同的value分配到一个组中,wordcount程序就利用了分组这一过程。
Shuffle-Combiner(组合):这一过程我们可以理解为一个小的Reduce阶段,当数据量大的时候可以在map过程中执行一次combine,这样就相当于在map阶段执行了一次reduce。由于reduce和map在不同的节点上运行,所以reduce需要远程拉取数据,combine就可以有效降低reduce拉取数据的量,减少网络负荷。(这一过程默认是不开启的,在如求平均值的mapreduce程序中不要使用combine,因为会影响结果。)
Compress(压缩):在缓冲区溢写磁盘的时候,可以对数据进行压缩,节约磁盘空间,同样减少给reducer传递的数据量。
Reduce-Merge(合并):reduce端会拉取各个map输出结果对应的分区文件,这样reduce端就会有很多文件,所以在此阶段,reduce再次阶段将它们合并,排序再送入reduce执行。
Output(输出):在reduce阶段,对已排序输出中的每个键调用reduce函数。此阶段的输出直接写到输出文件系统,一般为HDFS。

二、使用MapReduce实现WordCount

package org.example.hadoopdemo;

import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.*;

import java.io.IOException;
import java.util.Iterator;
import java.util.StringTokenizer;

public class WordCount
{
    public static class Map extends MapReduceBase implements Mapper<LongWritable,Text,Text,IntWritable>
    {
        private static final IntWritable  one = new IntWritable(1);
        private Text word = new Text();

        public void map(LongWritable longWritable, Text text, OutputCollector<Text, IntWritable> outputCollector, Reporter reporter) throws  IOException
        {
            String  line = text.toString();
            StringTokenizer st = new StringTokenizer(line);
            while(st.hasMoreTokens())
            {
                word.set(st.nextToken());
                outputCollector.collect(word,one);
            }
        }
    }

    public static class Reduce  extends MapReduceBase implements Reducer<Text,IntWritable,Text,IntWritable>
    {
        public void reduce(Text text, Iterator<IntWritable> iterator, OutputCollector<Text, IntWritable> outputCollector, Reporter reporter) throws  IOException
        {
            int sum = 0;
            while(iterator.hasNext())
            {
                sum += iterator.next().get();
            }
            outputCollector.collect(text,new IntWritable(sum));
        }
    }

    public static void main(String[] args)throws  Exception
    {
        JobConf jobConf = new JobConf(WordCount.class);
        jobConf.setJobName(args[0]);

        jobConf.setOutputKeyClass(Text.class);
        jobConf.setOutputValueClass(IntWritable.class);

        jobConf.setMapperClass(Map.class);
        jobConf.setReducerClass(Reduce.class);
        //可选的合并操作,可以减少map的输出结果迁移到reduce任务上的数据量
        //jobConf.setCombinerClass(Reduce.class);


        //设置输入format方式
        jobConf.setInputFormat(TextInputFormat.class);
        jobConf.setOutputFormat(TextOutputFormat.class);

        FileInputFormat.setInputPaths(jobConf,new Path(args[1]));
        FileOutputFormat.setOutputPath(jobConf,new Path(args[2]));
        JobClient.runJob(jobConf);
    }
}

TextInputFormat方式,文件的每一行会解析为一个键值对,key为该行在本文件中的偏移量,value为本行字符串。

三、MapReduce任务的优化

  包含计算性能的优化和IO操作的优化

 (1)任务调度的优化

     MapReduce在调度任务时,总会将任务优先分派给空闲的结点,在分配map任务时,优先分派给InputSpilt所在的机器

(2)数据预处理和Insplit的大小

   MapReduce适合处理少量的大数据,适当调节单个map任务处理数据的大小,可以提高程序运行效率。

   每一个InputSplit对应启动一个map任务。

   *决定map任务数量的因素

   (1)输入文件数目(2)输入文件的大小(3)配置参数 这三个因素决定的。
输入的目录中文件的数量决定多少个map会被运行起来,应用针对每一个分片运行一个map,一般而言,对于每一个输入的文件会有一个map split。如果输入文件太大,超过了hdfs块的大小(128M)那么对于同一个输入文件我们会有多余2个的map运行起来。

  

涉及参数:
mapreduce.input.fileinputformat.split.minsize //启动map最小的split size大小,默认0
mapreduce.input.fileinputformat.split.maxsize //启动map最大的split size大小,默认256M
dfs.block.size//block块大小,默认128M
计算公式:splitSize =  Math.max(minSize, Math.min(maxSize, blockSize))

    下面是FileInputFormat class 的getSplits()的伪代码: 
      num_splits = 0
      for each input file f:
         remaining = f.length
         while remaining / split_size > split_slope:
            num_splits += 1
            remaining -= split_size
      where:
        split_slope = 1.1 分割斜率
        split_size =~ dfs.blocksize 分割大小约等于hdfs块大小

会有一个比例进行运算来进行切片,为了减少资源的浪费
例如一个文件大小为260M,在进行MapReduce运算时,会首先使用260M/128M,得出的结果和1.1进行比较
大于则切分出一个128M作为一个分片,剩余132M,再次除以128,得到结果为1.03,小于1.1
则将132作为一个切片,即最终260M被切分为两个切片进行处理,而非3个切片。  

*reduce任务的数量

   reduce任务是一个数据聚合的步骤,默认为1,过多的reduce任务往往会带来复杂的数据shuffle和激增的输出文件。

  但我们仍然可以通过调节reduce任务的数量,提高程序运行的效率。

一个job的ReduceTasks数量是通过mapreduce.job.reduces参数设置
也可以通过编程的方式,调用Job对象的setNumReduceTasks()方法来设置
一个节点Reduce任务数量上限由mapreduce.tasktracker.reduce.tasks.maximum设置(默认2)。

可以采用以下探试法来决定Reduce任务的合理数量:
1.每个reducer都可以在Map任务完成后立即执行:
      0.95 * (节点数量 * mapreduce.tasktracker.reduce.tasks.maximum)
2.较快的节点在完成第一个Reduce任务后,马上执行第二个:
      1.75 * (节点数量 * mapreduce.tasktracker.reduce.tasks.maximum)

  两种探试方法基于不同的考量,

方式一、当一个任务失败时,JobTracker可以很快的找到一台空闲的TaskTracker结点重新执行失败的任务

方式二、使得执行速度快的TackTrackerke可以获取更多的reduce任务,因此使得负载更加均衡

(3)combine函数

     combine是一个可选的步骤,设置combine函数,会在将map的输出结果拷贝纸reduce任务之前进行合并操作,减少在网络上的数据传输量,这在map产生大量输出时是很有用的。

(4)压缩

    可以对map的输出结果和最终的输出结果设置指定的压缩方式,减少传输的数据量

四、基于Hadoop流的MapReduce

     Hadoop Stream API使用户可以使用任意可以从标准输入和标准输出流读取写入数据的语言复写map函数和reduce函数

   

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值