MapReduce

简介

一、概述

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

组件

一、序列化

  1. 在MapReduce中,要求数据能够被序列化
  2. MapReduce的序列化机制默认采用的AVRO
  3. MapReduce对AVRO的序列化机制进行了封装,提供了更简便的序列化形式 - 实现接口Writable

二、分区 - Partition

  1. 分区的作用是将数据进行分类
  2. 有无分区并不影响Map和Reduce的执行逻辑
  3. 分区默认是从0开始依次递增的
  4. 在MapReduce中,每一个分区要对应一个ReduceTask,每一个ReduceTask都会产生一个结果文件。默认情况下只有1个分区,也就只有1个ReduceTask,只产生一个结果文件
  5. 在MapReduce中,如果没有手动指定Partitioner,那么默认使用的分区类是HashPartitioner

三、排序

  1. 在MapReduce中,自动对键进行排序
  2. 要求键所对应的类必须实现Comparable接口,但是考虑到键需要序列化,所以一般实现的WritableComparable
  3. 在排序过程中,如果compareTo方法的返回值为0,则MapReduce会认为这两个键是同一个,则将这两个键的值放到一组,相当于去重过程
  4. 练习:按照月份升序排序,如果月份一样,则按照利润降序排序(文件:profit2.txt)

四、合并 - Combine

  1. 大多数情况下,MapTask的数量要远远多于ReduceTask的数量,导致计算压力几乎全部落在了ReduceTask上,ReduceTask的计算效率就成为整个MapReduce的瓶颈
  2. 合并的逻辑和Reducer的逻辑是一样的 - 只需要在Driver中添加job.setCombinerClass(Reducer.class);
  3. 合并的特点:减少数据总量但是不改变计算结果
  4. 如果进行汇总、获取最值、去重之类操作可以使用Combiner,但是例如求平均之类的操作不能使用Combiner

细节

一、数据本地化策略

  1. 当JobTracker收到MR程序的时候,会访问NameNode获取文件信息。文件信息包含文件大小以及块信息

  2. JobTracker对这个文件进行切片处理。注意:切片是逻辑切分不是物理切分。切片数量决定了MapTask的数量。默认情况下,Split和Block是等大的

  3. JobTracker会将划分出来的MapTask分配到TaskTracker上执行

  4. 因为MapTask在执行过程中需要读取数据,而数据在DataNode上,所以将DataNode和TaskTracker部署在相同的节点上以减少跨集群的网络传输

  5. 为了减少网络资源的消耗,在分配任务的时候会考虑Block的位置。哪个节点上有要处理的数据,将任务分配给哪个节点,这个过程称之为数据本地化

  6. 切片产生过程:
    a. 如果文件为空,则整个文件作为一个切片处理
    b. 在MapReduce中,文件要区分可切或者不可切,例如绝大部分的压缩文件就是不可切的
    c. 如果文件不可切,则整个文件作为一个切片处理
    d. 如果需要减小splitsize,需要调小maxsize;如果需要调大splitsize,需要调大minsize
    e. 在计算切片的时候,需要考虑切片阈值 - SPLIT_SLOP = 1.1

二、MR执行流程

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

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. 注意问题:
    a. spill过程不一定产生
    b. 默认情况下,溢写文件的大小不一定是80M,考虑序列化因素
    c. 缓冲区本质上是一个环形的字节数组,设置为环形的目的是为了避免寻址,能够重复利用缓冲区
    d. 阈值的作用是为了减少写入的阻塞

二、Reduce端的Shuffle

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

三、Shuffle的调优

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

InputFormat

一、概述

  1. InputFormat中定义了2个抽象方法:
    a. getSplits用于产生切片
    b. createRecordReader产生输入流读取切片

  2. InputFormat会把结果给到MapTask

  3. 实际过程中,如果需要自定义输入格式类,一般不是直接继承InputFormat而是继承它的子类FileInputFormat,这个子类中已经覆盖了getSplits方法,而只需要考虑如何读取数据即可

  4. 如果没有指定输入格式,那么默认使用的TextInputFormat。除了第一个切片对应的MapTask意外,其余的MapTask都是从当前切片的第二行开始读取到下一个切片的第一个行

  5. 多源输入下,允许输入不同格式的文件,但是文件格式可以不同Mapper类也可以不一样,但是最后交给Reducer处理的时候要一样

其他细节

一、数据倾斜

  1. 数据本身就有倾斜特性,即日常生活中所产生的数据本身就是不均等的
  2. 实际过程中,绝大部分的数据倾斜都会产生在Reduce端
  3. Map端产生倾斜的条件:多源输入、文件不可切且文件大小不均 - Map端的倾斜一旦产生无法解决 - 如果真的要解决,在特定条件下可以考虑缓存存根问题
  4. Reduce端的倾斜的本质是因为数据的倾斜性,但是直观原因是因为对数据进行了分类 - 分类规则往往是不可变的,所以在实际过程中往往考虑的是使用两阶段聚合 - 数据先打散后聚合

二、小文件

  1. 小文件的危害:
    a. 存储:大量小文件会产生大量的元数据,就导致内存被大量占用
    b. 计算:大量小文件就产生大量的切片,大量切片则意味着有大量的MapTask,会导致服务器的执行效率变低甚至会导致服务器崩溃
  2. 针对小文件的处理手段常见的有2种:合并和压缩
  3. Hadoop提供了一种原生的合并手段:Hadoop Archive,将多个小文件打成一个har包

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值