啥是map啥是reduce

mapredue是根据谷歌的三大论文里面的mapreduce paper的出来的一个hadoop计算引擎。

我们现在可以说是ZB时代了,日益所需的大数据时代让我们不得不使用分布式存储分布式计算分布式调度。以往的单台计算机已经存储不了我们的数据,也不能很快的计算我们想要实现的过程。

今天,就来讨论讨论分布式计算的mapreduce。

mapreduce分成map端和reduce端。

map端根据数据进行一些列操作,写入自己的磁盘。

然后reduce从map端把数据弄过来,也进行一些列操作。

这样原本的单台节点的工作量,就平均了好几台节点了。

å¨è¿éæå¥å¾çæè¿°

首先,我们来看看这张图。

最左边是一系列的split分片,可以看成一个个数据块,一般默认是64M,可能要看不同版本了,因为数据量现在越来越大,需要看看具体情况了。有时候设置为128M也不为过。

在每个split上我们可以定义自己的map函数,map任务就可以针对对应的split进行自己的逻辑操作。

下面我们就来看看整个图片的具体过程。

 


 

Map端


 

我们在进行分片后,我们需要进行map端的过程。

1:map根据都进来的一条条数据,分别有key和value,
然后执行自己的map函数里面的逻辑块,然后调用context.write将结果一条条输出去。

2:输出去是先写入一个环形的缓冲区,
当数据量达到唤醒缓冲区的80%时,就会开始向本地磁盘溢写。
在溢写过程中,会首先对数据进行Partition分区,即根据reduce的个数进行分区。
分区的方法可以自己实现一个partition然后在main里面设置分区就行,
mapreduce有自己默认的分区方法。

3:分区写数据时,还可以进行排序,也是可以自己定义排序方法。

4:分区写数据时,不仅可以排序,还可以进行combianer,
就是将同一个key的内容可以进行合并,相当于提前对相同key进行一个reduce。
比如,我如果有(a,1),(b,1),(a,1),(a,1)我如果不进行combianer,
那么传到reduce端的数据就是完完全全没有变得数据,3个a和1个b的数据,
但是如果我进行了combiner,那么就变成了(a,3),(b,1),那么传过去的就是1个a,1个b,
因为我把三个a的value进行了合并,这个合并方法可以自己定义的。
这样就减少了传输量,要知道,map端和reduce端不一定在同一个节点,
map端和reduce端是靠网络通信来实现数据传输的,所以你如果有些数据不进行combiner,
那么你的任务性能就可能下降许多。尤其是数据量很大的时候。

5:排序的过程是针对某一个分区进行排序,某一个分区会出现很多小文件,
小文件了会进行sort,combiner然后所有小文件汇总又会进行归并排序来合并文件。形成一个分区。

6:不同分区合在一起,等待reduce端来读取数据。

 

map端基本就结束了。


reduce过程


1:reduce先以http方式从map端磁盘读取对应属于自己分区的磁盘文件,放入内存缓冲区。

2:将读取过来的分区文件进行归并排序sort,并且进行combiner合并(当然combiner需要自己定义啦)。

3:然后作为reduce的输入文件,进行reduce逻辑操作,最终得出一个分区文件输出出去。

注意一个reduce就是要给分区,所以几个reduce就会在hdfs上对应几个输出的分区文件。

 

 



滴滴滴滴,休息一下。。。。。。。。。。。。。。。。

 



根据上面这几点,我们需要注意的是一个mapreduce过程,其实就是两个计算过程,然后其余基本就是排序,合并的过程了。

然而排序,合并又会设计到shuffle

shuffle就是清洗的意思,就是将数据重新清洗。打乱。

shuffle主要有map端,reduce端。。

 

 

 


map端shuffle


map端的shuffle就是在内存缓冲区达到一定量时,将数据根据partition实现方法进行分区,
分区数和reduce个数一样,并且数据会写道对应的分区。

 


reduce端shuffle


reduce端主要是从map端拉取数据,将不同节点但是是相同分区的数据拉取过来,进行sort和combiner。

 

 

 



下面我们用图形,把mapredcue的过程重新理一理



 

 

 

 

上面就用更详细的图,描述了具体过程,当然每个细节还有各种参数可以设置,也有很多注意点,以后遇到就慢慢探究。

比较重要的就是combiner,partition还有sort。

mapreduce的优化也是从这里进行优化的,拖慢mapreduce速度的就是shuffle的网络通信。我们可以想办法适当减少通信量来加快mapreduce执行速度。


wordcount例子


map程序

package com.hadoop.mapreduce;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

public class TestMapper extends Mapper<LongWritable, Text,Text,LongWritable> {
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        String line = value.toString();//先将Text类型转换为String
        String[] words = line.split(" ");//对每一行的数据以空格分割
        for(String word:words){
            context.write(new Text(word),new LongWritable(1));//将每一个单词以(word,1)的形式写出去。
        }
    }
}

reduce程序

package com.hadoop.mapreduce;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

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

public class TestRuduce extends Reducer<Text, LongWritable,Text,LongWritable> {
    @Override
    protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
        long num = 0;
        Iterator<LongWritable> iterator = values.iterator();
        while(iterator.hasNext()){
            num=num+iterator.next().get();//将每个迭代的加起来,就可以得出总的单词个数
        }
        System.out.println(key+"   "+num);
        context.write(key,new LongWritable(num));
    }
}

Runner

package com.hadoop.mapreduce;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;

public class Runner {
    //这个类就是程序的入口了
    public static void main(String[] args) {
        Configuration conf = new Configuration();
        conf.set("fs.defaultFS","hdfs://192.168.40.138:9000");

        //新建1一个job任务
        try {
            Job job = Job.getInstance(conf);
            //设置jar包
            job.setJarByClass(Runner.class);
            //指定mapper和reducer
            job.setMapperClass(TestMapper.class);
            job.setReducerClass(TestRuduce.class);

            //设置map端输出类型
            job.setMapOutputKeyClass(Text.class);
            job.setMapOutputValueClass(LongWritable.class);
            //设置reduce的输出类型
            job.setOutputKeyClass(Text.class);
            job.setOutputValueClass(LongWritable.class);

            //指定mapreduce程序的输入和输出路径
            Path inputPath = new Path("/wordcount/input");//这里是hdfs的路径,首先要将input这个文件传到hdfs上去
            Path outputPath = new Path("/wordcount/output");//这里也是hdfs路径,我们查看结果也需要在hdfs上查看。
            FileInputFormat.setInputPaths(job,inputPath);//设置输入路径,这里的输入路径和输出路径都mport org.apache.hadoop.mapreduce.lib.input下的,一定不要使用mapred下的,那是老包了,不要使用。
            FileOutputFormat.setOutputPath(job,outputPath);//设置输出路径

            //退后提交任务
            boolean waitForCompletion = job.waitForCompletion(true);
            System.exit(waitForCompletion?0:1);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

 

posted @ 2019-09-19 21:00  ongbo  阅读(162)  评论(0)    收藏  举报