MapReduce 框架 + 切片

MapReduce 框架原理:

​ 1、流程示意图

在这里插入图片描述

在这里插入图片描述

​ 2、流程详细

​ 上面的流程是整个 mapreduce 最全工作流程,但是 shuffle 过程只是从第 7 步开始到第 15 步结束,具体 shuffle 过程详解,如下:

​ 1)maptask 收集我们的 map() 方法输出的 KV 对,放到内存缓冲区中

​ 2)从内存缓冲区不断溢出本地磁盘文件,可能会溢出多个文件

​ 3)多个溢出文件会被合并成大的溢出文件

​ 4)在溢出过程中,及合并的过程中,都要调用 partitioner 进行分区和针对 key 进行排序

​ 5)reducetask 根据自己的分区号,去各个 maptask 机器上取相应的结果分区数据

​ 6)reducetask 会取到同一个分区的来自不同 maptask 的结果文件,reducetask 会将这些文件再进行合并(归并排序)

​ 7)合并成大文件后,shuffle 的过程也就结束了,后面进入 reducetask 的逻辑运算过程(从文件中取出一个一个的键值对 group,调用用户自定义的 reduce() 方法)

​ 3、注意

shuffle 中缓冲区大小会影响到 mapreduce 程序的执行效率,原则上说,缓冲区越大,磁盘 io 的次数越少,执行速度就越快。

​ 缓冲区的大小可以通过参数调整,参数:io.sort.mb 默认 **100M **。

InputFormat 数据输入(切片):

​ 1、切片计算公式

​ 1)找到里数据存储的目录。

​ 2)开始遍历处理(规划切片)目录下的每个文件

​ 3)遍历每个文件 ss.txt

​ (1)获取文件大小 fs.sizeOf(ss.txt);

​ (2)计算切片大小

computeSplitSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M

​ (3)默认情况下,切片大小=blocksize

​ (4)开始切,形成第 1 个切片:ss.txt — 0M:128M 第 2 个切片 ss.txt — 128M:256M 第 3 个切片 ss.txt — 256M:300M(每次切片时,都要判断切完剩下的部分是否大于快的 1.1 倍,不大于 1.1 倍就划分一块切片

​ (5)将切片信息写到一个切片规划文件中。

​ (6)整个切片的核心过程在 getSplit() 方法中完成。

​ (7)数据切片只是在逻辑上对输入数据进行分片,并不会在磁盘上将其切分成分片进行存储。InputSplit 只记录了分片的元数据信息,比如起始位置、长度以及所在的节点列表等。

​ (8)注意:block 是 HDFS 物理上存储的数据,切片是对数据逻辑上的划分

​ 4)提交切片规划文件到 yarn 上,yarn 上的 MrAppMaster 就可以根据切片规划文件计算开启 maptask 个数。

自定义 Partition(分区) :

​ 在前面代码的基础上增加 WordCountPartitioner 类:

/**
 * 根据数字的第一位的奇偶数进行分区
 * @author Jds
 */

public class WordCountPartitioner extends Partitioner<Text, IntWritable> {
    @Override
    public int getPartition(Text key,
                            IntWritable value,
                            int i) {

        String num = key.toString().substring(0, 1);

        // String --> Int
        int result = Integer.valueOf(num);

        if (result % 2 == 0 ){
            return 0;
        } else {
            return 1;
        }
    }
}

​ 向 WordCountDriver 类的代码中添加分区代码:

/**
 * @author Jds
 */

public class WordCountDriver {

    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {

        //输入数据的 Windows 路径,输出的 Windows 路径
        args = new String[]{"C:\\Users\\Jds\\Desktop\\mapreduce\\Partition.txt",
                "C:\\Users\\Jds\\Desktop\\mapreduce\\A2"};

        //获取配置信息
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);

        //反射三个类
        job.setJarByClass(WordCountDriver.class);
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);


        //Map 输出的 k,V 类型 Text, IntWritable 为 Reduce 的输入
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        //Reduce 输出的 K,V 类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        //设置分区(新添加项)
        job.setPartitionerClass(WordCountPartitioner.class);
        job.setNumReduceTasks(2);

        //数据的输入和输出指定目录
        FileInputFormat.setInputPaths(job,new Path(args[0]));
        FileOutputFormat.setOutputPath(job,new Path(args[1]));

        //提交 job ---> waitForCompletion 包含 submit() 两个都是提交
        job.waitForCompletion(true);
    }
}

Combiner 合并:

​ 将小文件进行合并,然后传给 Reduce ,减轻 Reduce 的工作量。

public class WordCountDriver {

    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {

        //输入数据的 Windows 路径,输出的 Windows 路径
        args = new String[]{"C:\\Users\\Jds\\Desktop\\mapreduce\\Text\\",
                "C:\\Users\\Jds\\Desktop\\mapreduce\\A1"};

        //获取配置信息
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);

        //反射三个类
        job.setJarByClass(WordCountDriver.class);
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);


        //Map 输出的 k,V 类型 Text, IntWritable 为 Reduce 的输入
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        //Reduce 输出的 K,V 类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        /**
        * Combiner
        */
        job.setCombinerClass(WordCountReducer.class);

        //设置分区
        ///job.setPartitionerClass(WordCountPartitioner.class);
        //job.setNumReduceTasks(2);

        //数据的输入和输出指定目录
        FileInputFormat.setInputPaths(job,new Path(args[0]));
        FileOutputFormat.setOutputPath(job,new Path(args[1]));

        //提交 job ---> waitForCompletion 包含 submit() 两个都是提交
        job.waitForCompletion(true);
    }
}

InputFormat 切片机制 :

​ 关于大量小文件的优化策略。

​ 1、默认情况下 TextInputformat 对任务的切片机制是按文件规划切片,不管文件大小,都会是一个单独的切片,都会交给一个 maptask ,这样如果有大量小文件,就会产生大量的 maptask ,处理效率极其低下。

​ 2、优化策略

​ 1)最好的办法,在数据处理系统的最前端(预处理/采集),将小文件先合并成大文件,再上传到 HDFS 做后续分析。

​ 2)补救措施:如果已经是大量小文件在 HDFS 中了,可以使用另一种 InputFormat 来做切片(CombineTextInputFormat),它的切片逻辑跟 TextFileInputFormat 不同:它可以将多个小文件从逻辑上规划到一个切片中,这样,多个小文件就可以交给一个 maptask 。

​ 3)优先满足最小切片大小,不超过最大切片大小:

​ CombineTextInputFormat.setMaxInputSplitSize(job,3*1024*1024)

​ CombineTextInputFormat.setMinInputSplitSize(job,2*1024*1024)

​ 3、具体实现步骤

//  如果不设置InputFormat,它默认用的是TextInputFormat.class
job.setInputFormatClass(CombineTextInputFormat.class)
CombineTextInputFormat.setMaxInputSplitSize(job, 3*1024*1024);// 3m
CombineTextInputFormat.setMinInputSplitSize(job, 2*1024*1024);// 2m

:在看 number of splits 时,和最大值(MaxSplitSize)有关、总体规律就是低于最大值是一片高于最大值 1.5 倍 + ,则是两片高于最大值 2 倍以上则向下取整,比如文件大小为 65MB ,切片最大值为 4MB ,那么切片为 16 个。总体来说,切片差值不超过 1 个,不影响整体性能

规律片数 = 文件的大小 / 最大值

public class WordCountDriver {

    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {

        //输入数据的 Windows 路径,输出的 Windows 路径
        args = new String[]{"C:\\Users\\Jds\\Desktop\\mapreduce\\Text\\",
                "C:\\Users\\Jds\\Desktop\\mapreduce\\A1"};

        //获取配置信息
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);

        //反射三个类
        job.setJarByClass(WordCountDriver.class);
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);


        //Map 输出的 k,V 类型 Text, IntWritable 为 Reduce 的输入
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        //Reduce 输出的 K,V 类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        //Combiner
///        job.setCombinerClass(WordCountReducer.class);

        /**
        * 切片优化 如果不设置InputFormat,它默认用的是TextInputFormat.class
        */
        job.setInputFormatClass(CombineTextInputFormat.class);
        CombineTextInputFormat.setMaxInputSplitSize(job,3*1024*1024);
        CombineTextInputFormat.setMinInputSplitSize(job,2*1024*1024);

        //设置分区
        ///job.setPartitionerClass(WordCountPartitioner.class);
        //job.setNumReduceTasks(2);

        //数据的输入和输出指定目录
        FileInputFormat.setInputPaths(job,new Path(args[0]));
        FileOutputFormat.setOutputPath(job,new Path(args[1]));

        //提交 job ---> waitForCompletion 包含 submit() 两个都是提交
        job.waitForCompletion(true);
    }
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值