09-Hadoop-MapReduce的设计理念和详细的计算流程

6.2 MapReduce的计算流程⭐️

面试题常见

问题:计算1T数据中每个单词出现的次数–> wordcount

6.2.1原始数据File

1T数据被切分成块存放在HDFS上,每一个块有128M大小

6.2.2 数据库Block

  1. HDFS上数据存储的一个单元,同一个文件中块的大小都是相同的
  2. Block块存在的问题
    • 因为数据存储到HDFS上不可变,所以有可能块的数量和集群的计算能力不匹配
    • 所以我们需要一个动态调整本次参与计算节点数量的一个单位
    • 同时,我们也可以动态的改变这个参与节点的单位(split)

6.2.3 切片Split

  1. 定义理解:

    • 切片是一个逻辑概念,指的是文件中数据偏移量范围,并不是物理上的切分
    • 在不改变现在数据存储的情况下,可以控制参与计算的节点数目
    • 对于HDFS中存储的一个文件,要进行Map处理前,需要将它切分成多个块,才能分配给不同的MapTask去执行。
    • 在执行MapReduce之前,原始数据会被切分成若干个split,每个split作为一个MapTask的输入,在Map执行过程中split会被分解成一个个记录(key-value的键值对,其中key是偏移量,不是行数),Map会依次处理每一个记录,
    • split记录了要处理的数据的位置和长度
  2. 作用:

    • 通过切片大小可以达到控制计算节点数量的目的
    • 有多少个切片就会执行多少个Map任务(一对一)
    • split划分可以让MapTask更好地获取数据输入
  3. 切片产生的原因:

  4. 切片的大小

    • 一般切片的大小为Block块的整数倍(2倍或者1/2倍)
      • 防止多余创建和很多的数据连接
    • 默认情况下,Split切片的大小等于Block的大小,默认128M
    • 如果Split大小>Block大小,则相对于Split=Block来说,计算的Map节点少了
    • 如果Split大小<Block大小,则相对于Split=Block来说,计算的Map节点多了
    • 一个切片对应一个MapTask
  5. 切片中1.1倍的理解

    每次切片的时候,都要判断前一个切片切完之后剩余的部分是否大于块(默认切片的块大小相同)的1.1倍,如果不大于块的1.1倍,就把剩余的部分切分到一个块中,避免很小的一部分也要切片,提高效率

    举例:

  6. MapReduce如何处理跨行的Block和split?

    • 问题解析:Map读取数据是按照一行一行来读取数据的,当一行数据被切分成了两个split时Map如何读取数据?
    • 通俗解答:如果Map在读取数据的时候发现有一行数据被切分成了两个split,在读取数据时发现有一行没有读完(没有遇到换行符\n),就会去下一个split中读取这一行接着读取没有读取完的数据,直到遇到换行符\n,这一行才读取完毕。第二个Map读取数据的时候就会查看上一个Map的最后一行是不是有换行符,如果没有,则说明第二个split的第一行内容已经被上一个Map读取过了,这时第二个Map会从已经读取过的这行的下一行开始读取

    image-20220622194509124

6.2.4 MapTask

image-20220620194455154

  1. 定义理解:
    • 数据拆分计算
    • Map默认从所属切片读取数据,每次读取一行(默认读取器)到内存中,我们可以对这一行数据进行拆分操作

6.2.5 环形数据缓冲区

  1. 定义理解:

    • MapOutputBuffer内部使用了一个缓冲区暂时存储用户输出数据,当缓冲区使用率达到一定阈值后,再将缓冲区中的数据写到磁盘上。
  2. 作用:

    • 可以利用这块内存区域,减少数据溢写时Map的停止时间
    • 数据可以循环写到硬盘,不用担心OOM的问题
    • 在有效的空间内,能够更加高效的在内存中执行操作
  3. 大小设置:

    • 在内存中构建一个环形数据缓冲区(kvBuffer),默认大小为100M
    • 设置缓存区的阈值为80%,当缓冲区的数据达到80M时开始向外溢写到硬盘,溢写的时候还有20M的空间可以被使用,效率并不会被减缓
    img

6.2.6 分区Partition

  1. 定义理解:

  2. 作用:

    • 根据Key直接算出这个数据所对应的Reduce
    • 方便以后数据的拉取,应该将相同分区的数据放到一起
  3. 特点

    • 分区的数量和Reduce的数量是相等的,一个分区对应一个Reduce
      • 如果我们的MapReduce操作只有一个Reduce操作,Partation就只有一个,如果我们有多个Reduce操作,就会有多个Partition。Partition因此就是Reduce的输入分片,这个程序员可以编程控制,主要是根据实际key和value的值,根据实际业务类型或者为了更好的reduce负载均衡要求进行,这是提高reduce效率的一个关键所在
    • 默认分区的算法是Hash,然后取余
      • hash(key) % Partition= num
    • 如果两个对象equals,那么两个对象的hashcode一定相等
    • 如果两个对象的hashcode相等,但是对象不一定equlas

6.2.7 排序 Sort

  1. 定义理解:

  2. 排序步骤:

    • 对要溢写的数据进行排序(快速排序)
    • 然后先分区Partation后,按照Key的顺序排序,相同的分区在一起,相同的Key在一起
  3. 注意:

    • 我们将来溢写出的小文件也是有序的

6.2.8 溢写 Spill

  1. 定义理解:

    • Spill过程要结合环形数据缓冲区理解,
    • map还会为输出操作启动一个守护线程,如果缓冲区的内存达到了阀值的80%时候,这个守护线程就会把内容写到磁盘上,这个过程叫spill
    • 环形缓冲区的数据到达80%时,就会溢写到本地磁盘,当再次达到80%时,就会再次溢写到磁盘, 直到最后一次,不管环形缓冲区还有多少数据,都会溢写到磁盘。然后会对这多次溢写到磁盘的多个小文件进行合并,减少Reduce阶段的网络传输。
  2. 作用:

    • 将内存中的数据循环写到硬盘,不用担心OOM的问题
  3. 注意:

    • 每次会产生一个80M的文件
    • 如果本次Map产生的数据较多,可能会溢写多个文件
    • 如果环形缓冲区的数据没有达到80%的阶段就结束了,这时就直接把环形缓冲区的数据写到磁盘上,供下一步使用

6.2.9 合并 Merge

  1. 定义理解:

  2. 合并的原因:

    • 因为溢写回产生很多有序(分区 key)的小文件,而且小文件的数目不确定,后面向Reduce传递数据的时候会带来很大问题
    • 所以将小文件合并成一个大文件,将来拉取的时候数据直接从大文件拉取即可
      • 合并小文件的时候同样进行排序(归并排序),最终产生一个有序的大文件
    • 原因的深入理解:
      • 把溢写出的文件合并到一起形成一个总的结果,这就意味着要么把这些数据调到一台机器上进行汇总(所有单词都在一个机器上进行统计),要么将不同部分的数据在不同节点上汇总(这几个单词在这台机器上统计,其他单词在另外一台机器上统计)。如果是前者,汇总的那一台机器的负载会很高,如果后者,还需要写一个中间数据的调度系统。
      • 参考资料: 为什么要用MapReduce以及MapReduce的切片_黑白键的约定的博客-CSDN博客

6.2.10 组合器 combiner

6.2.11 拉取 Fetch

image-20220620203313583

  1. 定义理解:

    • 我们需要将Map的临时结果 拉取到Reduce节点
  2. 原则:

    • 相同的key必须拉取到同一个Reduce节点
    • 但是一个Reduce节点可以有多个key
  3. 未排序前的数据处理

    • 未排序前,需要拉取数据的时候必须对Map产生的最终的合并文件做全序遍历(这样相比于先快排,再归并,效率低很多)
    • 而且每一个Reduce都要做一个全序遍历
    • 如果Map产生的大文件是有序的,那么每一个Reduce只需要从文件中读取自己所需的即可(效率将大大提升)

6.2.12再次合并 Merge

  1. 原因:
    • 因为Reduce拉取的时候,会从多个Map拉取数据,那么每个Map都会产生一个小文件,这些小文件之间无序,文件内部有序
    • 为了方便计算(没必要读取N个小文件),所以需要合并
  2. 归并算法合并
    • 相同的key都在一起

6.2.13 写出Output

  • 每个Reduce将自己计算的最终结果都会存放到HDFS上

6.2.14 MapReduce的过程图解

  1. 图解1:
image-20220620204548001
  1. 图解2:

image-20220620204515367

  1. 图解3:

    image-20220620204749975

详细过程图解:

image-20220620204633490

6.15 MapReduce的工作流程总结 ☕️

  1. 客户端将每个block块切片(逻辑切分),每个切片都对应一个map任务,默认一个block块对应一个切片和一个map任务,split包含的信息:分片的元数据信息,包含起始位置,长度,和所在节点列表等

  2. map按行读取切片数据,组成键值对,key为当前行在源文件中的字节偏移量,value为读到的字符串

  3. map函数对键值对进行计算,输出<key,value,partition(分区号)>格式数据,partition指定该键值对由哪个reducer进行处理。通过分区器,key的hashcode对reducer个数取模。

  4. map将kvp写入环形缓冲区内,环形缓冲区默认为100MB,阈值为80%,当环形缓冲区达到80%时,就向磁盘溢写小文件,该小文件先按照分区号排序,区号相同的再按照key进行排序,归并排序。溢写的小文件如果达到三个,则进行归并,归并为大文件,大文件也按照分区和key进行排序,目的是降低中间结果数据量(网络传输),提升运行效率

  5. 如果map任务处理完毕,则reducer发送http get请求到map主机上下载数据,该过程被称为洗牌shuffle

  6. 可以设置combinclass(需要算法满足结合律),先在map端对数据进行一个压缩,再进行传输,map任务结束,reduce任务开始

  7. reduce会对洗牌获取的数据进行归并,如果有时间,会将归并好的数据落入磁盘(其他数据还在洗牌状态)

  8. 每个分区对应一个reduce,每个reduce按照key进行分组,每个分组调用一次reduce方法,该方法迭代计算,将结果写到hdfs输出

6.16 shuffle洗牌过程 ☕️

  1. copy:一个reduce任务需要多个map任务的输出,每个map任务完成时间很可能不同,当只要有一个map任务完成,reduce任务立即开始复制,复制线程数配置mapred-site.xml参数“mapreduce.reduce.shuffle.parallelcopies",默认为5.

  2. copy缓冲区:如果map输出相当小,则数据先被复制到reduce所在节点的内存缓冲区大小配置mapred-site.xml参数“mapreduce.reduce.shuffle.input.buffer.percent”,默认0.70),当内存缓冲区大小达到阀值(mapred-site.xml参数“mapreduce.reduce.shuffle.merge.percent”,默认0.66)或内存缓冲区文件数达到阀值(mapred-site.xml参数“mapreduce.reduce.merge.inmem.threshold”,默认1000)时,则合并后溢写磁盘。

  3. sort:复制完成所有map输出后,合并map输出文件并归并排序

  4. sort的合并:将map输出文件合并,直至≤合并因子(mapred-site.xml参数“mapreduce.task.io.sort.factor”,默认10)。例如,有50个map输出文件,进行5次合并,每次将10各文件合并成一个文件,最后5个文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值