大数据-什么是MapReduce?&&数据本地化&MapReduce原理及执行流程&&Shuffle的调优

一、什么是MapReduce?


一、概述

  1. MapReduce是Hadoop提供的一套用于进行分布式计算的框架
  2. 将计算过程拆分为2个阶段:Map映射阶段和Reduce规约阶段
  3. 如图所示:

    MapReduce在对文件进行计算的时候,会先将文件进行切片,切片和切块不一样,每个切片对应MapTask默认情况下,每一个MapTask在拿到切片之后会进行按行读取按行处理

二、MapReduce的数据本地化


二、数据本地化策略

  1. 当JobTracker收到MR程序的时候,会访问NameNode获取文件信息。文件信息包含文件大小以及块信息
  2. JobTracker对这个文件进行切片处理。注意:切片是逻辑切分不是物理切分。切片数量决定了MapTask的数量。默认情况下,Split和Block是等大的
  3. JobTracker会将划分出来的MapTask分配到TaskTracker上执行
  4. 因为MapTask在执行过程中需要读取数据,而数据在DataNode上,所以将DataNode和TaskTracker部署在相同的节点上以减少跨集群的网络传输
  5. 为了减少网络资源的消耗,在分配任务的时候会考虑Block的位置。哪个节点上有要处理的数据,将任务分配给哪个节点,这个过程称之为数据本地化
  6. 切片产生过程:
    1. 如果文件为空,则整个文件作为一个切片处理
    2. 在MapReduce中,文件要区分可切或者不可切,例如绝大部分的压缩文件就是不可切的
    3. 如果文件不可切,则整个文件作为一个切片处理
    4. 如果需要减小splitsize,需要调小maxsize;如果需要调大splitsize,需要调大minsize
    5. 在计算切片的时候,需要考虑切片阈值 - SPLIT_SLOP = 1.1

三、MapReduce原理及执行流程


  1. 准备阶段:
    1. 检查输入和输出路径
    2. 计算切片数量
    3. 如果有必要,设置缓存存根
    4. 将jar包和配置上传到HDFS上
    5. 将任务提交给JobTracker,并且可以选择是否监控这个任务
  2. 执行阶段:
    1. JobTracker收到Job任务之后,会将这个任务进行拆分,拆分成MapTask和ReduceTask。MapTask的数量由切片决定;ReduceTask的数量由分区数量决定
    2. JobTracker在拆分完成任务之后,会等待TaskTracker的心跳,然后给TaskTracker分配任务。分配任务的时候,MapTask尽量满足数据本地化策略,ReduceTask无法满足数据本地化,所以ReduceTask在分配的时候是考虑节点的空闲
    3. TaskTracker通过心跳领取任务,领取到任务之后,会去对应节点上下载jar包,这一步体现的思想是逻辑移动数据固定
    4. TaskTracker会在本节点上开启JVM子进程执行MapTask或者ReduceTask。注意:每一个MapTask或者ReduceTask的执行都会开启一次JVM子进程
  3. 执行流程原理图,(下图是我自己理解并且绘制的,大家可以参考 自己思考绘制,会有不一样的理解)

  4. 图太小看不清可参考下面网址(本人感觉这篇对MapReduce的理解还算透彻)

                MR的原理和运行流程:https://blog.csdn.net/qq_31975963/article/details/84995460#MR_2

               一起学Hadoop——MapReduce原理:https://zhuanlan.zhihu.com/p/42864264

四、Shuffle介绍及Shuffle的调优


一、Map端的Shuffle

  1. map方法在处理完成数据之后会将结果写出到MapTask自带的缓冲区中 - 每一个MapTask自带一个缓冲区 - MapOutputCollector
  2. 数据在缓冲区中进行分区、排序,如果指定了Combiner,那么数据在缓冲区中还会进行combine。注意:在缓冲区中的排序是将完全无序的数据整理成有序数据,采取的是快速排序
  3. 缓冲区是维系在内存中,默认是100M
  4. 当缓冲区的使用达到一定限度(溢写阈值:0.8)的时候,会将缓冲区中的数据溢写(spill)到磁盘上,map方法后续产生的结果会继续写到缓冲区中
  5. 每一次溢写都会产生一个新的溢写文件 - 单个溢写文件中的数据是分区且有序的,所有的溢写文件之间是局部有序的
  6. 在map方法完成之后,将所有的溢写文件进行合并(merge),将所有的溢写文件合并成一个结果文件(final out),在merge过程中,数据会再次进行分区排序 - final out是整体分区且有序的。merge过程中的排序是将局部有序变成整体有序,所以采用的是归并排序
  7. 如果map方法执行完成之后,缓冲区中依然有数据,则会直接合并到最后的final out中
  8. 在merge过程中,如果spill文件个数>=3并且指定了Combiner,则在merge的时候会再进行一次combine
  9. 注意问题:
    1. spill过程不一定产生
    2. 默认情况下,溢写文件的大小不一定是80M,考虑序列化因素
    3. 缓冲区本质上是一个环形的字节数组,设置为环形的目的是为了避免寻址,能够重复利用缓冲区
    4. 阈值的作用是为了减少写入的阻塞

二、Reduce端的Shuffle

  1. ReduceTask启动多个fetch线程去MapTask处抓取对应分区的数据
  2. ReduceTask将从每一个MapTask上抓取过来的数据存储在一个本地文件中
  3. 将抓取来数据进行一次merge,合并成一个大文件,在merge过程中,会再次进行排序,采用的是归并排序
  4. merge完成之后,ReduceTask会再将相同的键对应的值放到一个迭代器中,这个过程称之为分组(group)
  5. 分组完成之后,每一个键对应一个迭代器,每一个键调用一次reduce方法
  6. 注意问题:
    1. ReduceTask的启动阈值:0.05 - 当5%的MapTask结束,就会启动ReduceTask去抓取数据
    2. fetch线程通过HTTP请求获取数据
    3. fetch线程的数量默认为5
    4. merge因子:10 - 每10个小文件合并成1个大文件

三、Shuffle的调优

  1. 减少溢写次数:
    1. 增大缓冲区,实际过程中缓冲区的大小一般是在250~400M之间
    2. 增大缓冲区阈值,同时增加了写入阻塞的风险 - 不建议
    3. 增加Combine的过程
  2. 可以考虑将Map的结果文件进行压缩,这个方案是在网络资源和CPU资源之间的取舍
  3. 增加fetch线程的数量
  4. 增大merge因子,会增加底层计算的复杂度 - 不建议
  5. 减小ReduceTask的启动阈值,增加了ReduceTask的阻塞风险 - 不建议

猜你喜欢

转载自blog.csdn.net/weixin_47055922/article/details/108322533