MapReduce的工作原理及实现案例

本文详细解读了MapReduce的执行流程,包括计算分片、map、shuffle、partition、combiner和reduce阶段,以及WordCount示例。同时介绍了优化策略,如数据输入合并、减少I/O操作和解决数据倾斜的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MapReduce的框架原理

在这里插入图片描述

执行流程

  1. [split]计算分片

     在map之前,根据输入文件创建inputSplit
     ➢每个InputSplit对应一个Mapper任务
     ➢输入分片存储的是分片长度和记录数据位置的数组
    
     block和split的区别
     1、block是数据的物理表示
     2、split是块中数据的逻辑表示
     3、split划分是在记录的边界处
     4、split的数量应不大于block的数量(一般相等)
    
  2. [map]调用map()方法对数据进行处理

     MapTask并行度由客户端提交job时的切片个数决定
     MapTask工作机制:Read读取阶段->Map处理阶段->Collect收集阶段->Spill溢写阶段->Combine阶段
    
  3. [shffule]主要负责将map端生成的数据传递给reduce端

    • Partition 分区:用于在Map端对key进行分区

        ➢默认使用的是HashPartitioner
        	获取key的哈希值 
        	使用key的哈希值对Reduce任务数求模
        ➢自定义Partitioner
        	继承抽象类Partitioner,重写getPartition方法
        	job.setPartitionerClass(MyPartitioner.class)
      
    • Combiner 合并:是对每一个 maptask 的输出先进行局部汇总,以减小网络传输量

       Combiner和Reducer的区别在于运行的位置:
       ➢ Combiner 是在每一个MapTask所在的节点运行;
       ➢ Reducer是接收全局所有Mapper的输出结果
      
  4. [reduce]对Shffule阶段传来的数据进行最后的整理合并

     *ReduceTask的数量可以直接手动设置:job.setNumReduceTasks(num);
     1、reducetask=0 ,表示没有 reduce 阶段,输出文件个数和 map 个数一致
     2、reducetask 默认值就是 1,所以输出文件个数为一个
     3、如果数据分布不均匀,就有可能在 reduce 阶段产生数据倾斜
     4、如果分区数不是1,但是reducetask为1,不执行分区过程
     *ReduceTask工作机制:Copy阶段->Merge阶段->Sort阶段->Reduce阶段
    

在这里插入图片描述

MapReduce具体工作流程

1、Client向ResourceManager提交任务申请,RM找到NodeManager并启动一个
AppMaster,AM通过获取到的分片信息,向RM申请资源,并启动相应数量的maptask
和ReduceTask;
2、在maptask上读取文件,由TextInputFormat指定读取规则,调用RecordReader
方法按行读取,将行号和每行数据组成文件块进行返回,返回的LongWritable和Text
将作为Mapper中map方法的入口数据;
3、每次获取的行的偏移量和每一行内容通过map()方法进行逻辑运算形成新的键值
对,通过context对象写到OutputCollector中;
4、OutputCollector把收集到的键值对发送到环形缓冲区,就进入了shuffle过程.
环形缓冲区的默认大小为100M,当数据累计到其大小的80%,就会触发溢出;
5、spill溢出前是需要对数据进行分区和排序的,如果没有设置分区器,就会调用系统
默认的分区方法,对环形缓冲区的每个键值对hash一个partition值,相同值得分为同
一个区,分区数跟NumReduceTasks相关。然后再对Key值进行升序排序;
6、环形缓冲区中分区排序后的数据溢出到文件中,如果map阶段处理的数据量较大,
则会溢出多个小文件。如果设置了combiner,相同Key的value值相加,当处理数据量
较大时,目的是让尽可能少的数据写入到磁盘,提高运行效率,否则文件中将存在多个
相同的Key;
7、多个溢出的小文件会被归并排序为一个大文件,大文件中的数据仍然是分区且分
区有序的;
8、当mrAppmaster监控到所有的map task任务完成后,reduce task会根据自己的分
区号去每个不同的map task节点上去取相同分区的数据,然后将取过来的数据在进行
merge合并成一个大文件,大文件是按照k有序的,此时,shuffle过程结束;
9、在reduce task运算过程中,首先调用groupingComparator对大文件的数据进行
分组,每次取出一组键值,通过自定义的reduce()方法进行逻辑处理,然后根据
OutPutFormat指定的输出格式将数据写到hdfs文件中。输出文件的个数与reduce
个数一致。

WordCount的MapReduce代码实现

public class WordMapper extends Mapper<LongWritable, Text,Text, IntWritable> {
    //LongWritable, Text(输入类型,行号和每一行内容),Text, IntWritable(输出类型)
    private Text word = new Text();
    private IntWritable count = new IntWritable(1);

    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        String[] words = value.toString().replaceAll(",|\"|\\.|\\?|!|:|;","").split(" ");
        for (String _word : words) {
            word.set(_word);
            //向reducer传输内容
            context.write(word,count);
        }
    }
}
public class WordReducer extends Reducer<Text, IntWritable,Text,IntWritable> {
    private IntWritable count = new IntWritable(0);

    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
        int sum = 0;
        for(IntWritable value:values){
            sum += value.get();
        }
        count.set(sum);
        context.write(key,count);
    }
}
public class WordTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {

        //创建HDFS访问路径配置信息
        Configuration config = new Configuration();
        config.set("fs.defaultFS","hdfs://192.168.37.200:9000");
        //创建mapreduce计算任务
        Job job = Job.getInstance(config,"wordCount");
        //设置主类,定位外部jar资源
        job.setJarByClass(WordTest.class);
        //设置任务数:和文件分片数和所存储的DN数有关
        job.setNumReduceTasks(2);
        //设置分区器Partitioner
        job.setPartitionerClass(WordPartitioner.class);
        //设置Combiner
        job.setCombinerClass(WordReducer.class);
        //设置mapper
        job.setMapperClass(WordMapper.class);
        //设置reducer
        job.setReducerClass(WordReducer.class);
        //设置mapper输出键值类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        //设置reducer输出键值类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
        //设置HDFS输入文件绑定job
        FileInputFormat.setInputPaths(job,new Path("/kb10/Pollyanna.txt"));
        FileOutputFormat.setOutputPath(job,new Path("/kb10/wordCount2"));
        //等待所有job步骤完成
        System.out.println(job.waitForCompletion(true));
    }
}

MapReduce优化

  • 数据输入

      合并小文件:在执行mr任务前将小文件进行合并
    
  • Map阶段

     1.减少溢写(spill)次数
     2.减少合并(merge)次数
     3.map之后先进行combine处理,减少 I/O
    
  • Reduce阶段

     合理设置map和reduce数
     合理设置reduce端的buffer
    
  • IO传输

      尽量避免IO传输
    
  • 数据倾斜问题

     数据频率倾斜—某一个区域的数据量要远远大于其他区域
     数据大小倾斜—部分记录的大小远远大于平均值
     解决数据倾斜问题:
     方法1:抽样和范围分区
     方法2:自定义分区
     方法3:Combine
     方法4:采用Map Join
    
  • 常用的调优参数

      资源相关参数
      shuffle性能优化的关键参数
      容错相关参数
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值