原理图:

中间结果的排序与溢出(spill)流程图

map分析:

(1)、输入分片(input split):在进行mapreduce之前,mapreduce首先会对输入文件进行输入分片(input split)操作,每一个输入分片针对一个map任务,输入分片(input split)存储的并非数据本身,而是一个分片长度和一个记录数据的位置的数组,对于输入文件的分片大小,通常跟hdfs的块大小有关系,例如:hdfs的块大小为64MB,假如输入三个文件,1MB、98MB的文件,mapreduce就会对1MB的文件当作一个input split,对98MB的文件做两个input split(可以通过修改参数mapreduce.input.fileinputformat.split.minsize,使其大于块容量;由于CPU的约束,有时可以减少fileinputformat.split.minsize属性值,使它小于HDFS的块容量,从而提高资源的利用率。)。针对这三个分片操作,就有三个map任务要执行,但是这里每一个map任务执行的数据大小并不均匀,这里也是一个调优的重点。

(2)、map阶段就是通过程序员定义好的map函数输出键值<k1,v1>对了。每一个map task有一个环形内存缓冲区,用于存放map task的输出,也就是键值对<k2,v2>,已经被序列化,但没有排序。环形缓冲区默认大小100MB(mapreduce.task.io.sort.mb属性),一旦达到阀值0.8(mapreduce.map.sort.spill.percent属性),一个后台线程就把溢出(spill)内容写到Linux本地磁盘中的指定目录(mapreduce.cluster.local.dir)下的新建的一个溢出写文件,当超过阈值时,Map任务不会因为缓存溢出而被阻塞。但如果达到硬限制,Map任务会被阻塞,直到溢出行为结束。缓存的好处就是减少磁盘I/O的开销,提高合并和排序的速度。又因为默认的内存缓冲大小是100M(当然这个是可以配置的),所以在编写map函数的时候要尽量减少内存的使用,为shuffle过程预留更多的内存,因为该过程是最耗时的过程。

♥   线程会将记录基于键进行分区(通过 mapreduce.job.partitioner.class设置分区算法的类),在内存中将每个分区的记录按键排序(通过map.sort.class指定排序算法,默认快速排序org.apache.hadoop.util.QuickSort),然后写入一个文件。每次溢出,都有一个独立的文件存储。

♥   Map任务完成后,缓存溢出的各个文件会按键排序后合并到一个输出文件(通过mapreduce.cluster.local.dir指定输出目录,值为${hadoop.tmp.dir}/mapred/local)。合并文件的流的数量通过mapreduce.task.io.sort.factor指定,默认10,即同时打开10个文件执行合并。

说白点就是:在写磁盘前,要进行partition、sort和combine等操作。通过分区,将不同类型的数据分开处理,之后对不同分区的数据进行排序,如果有Combiner,还要对排序后的数据进行combine。等最后记录写完,将全部溢出文件合并为一个分区且排序的文件。(注意:在写磁盘的时候采用压缩的方式将map的输出结果进行压缩是一个减少网络开销很有效的方法!)

根据上面步骤,最好仅在Map任务结束的时候才能缓存写到磁盘中。

可以采用以下方法提高排序和缓存写入磁盘的效率:

  1. 调整mapreduce.task.io.sort.mb大小,从而避免或减少缓存溢出的数量。当调整这个参数时,最好同时检测Map任务的JVM的堆大小,并必要的时候增加堆空间。
  2. mapreduce.task.io.sort.factor属性的值提高100倍左右,这可以使合并处理更快,并减少磁盘的访问。
  3. 为K-V提供一个更高效的自定义序列化工具,序列化后的数据占用空间越少,缓存使用率就越高。
  4. 提供更高效的Combiner(合并器),使Map任务的输出结果聚合效率更高。
  5. 提供更高效的键比较器和值的分组比较器。

注:

如果指定了Combiner,可能在两个地方被调用。

  1. 当为作业设置Combiner类后,缓存溢出线程将缓存存放到磁盘时,就会调用;
  2. 缓存溢出的数量超过mapreduce.map.combine.minspills(默认3)时,在缓存溢出文件合并的时候会调用Combiner。

1、获取中间输出结果(Map侧)

Reducer需要通过网络获取Map任务的输出结果,然后才能执行Reduce任务,可以通过下述Map侧的优化来减轻网络负载:

  1. 通过压缩输出结果,mapreduce.map.output.compress设置为true(默认false),mapreduce.map.output.compress.codec指定压缩方式。
  2. Reduce任务是通过HTTP协议获取输出分片的,可以使用mapreduce.tasktracker.http.threads指定执行线程数(默认40)

reduce阶段:

Reduce任务是一个数据聚合的步骤。数量默认为1,而使用过多的Reduce任务则意味着复杂的shuffle,并使输出文件的数量激增。mapreduce.job.reduces属性设置reduce数量,也可以通过编程的方式,调用Job对象的setNumReduceTasks()方法来设置。一个节点Reduce任务数量上限由mapreduce.tasktracker.reduce.tasks.maximum设置(默认2)。

可以采用以下探试法来决定Reduce任务的合理数量:

# 每个reducer都可以在Map任务完成后立即执行
0.95 * (节点数量 * mapreduce.tasktracker.reduce.tasks.maximum)

另一个方法是

# 较快的节点在完成第一个Reduce任务后,马上执行第二个
1.75 * (节点数量 * mapreduce.tasktracker.reduce.tasks.maximum)

2. 获取中间输出结果(Reduce侧)

Reduce任务在结束时都会获取Map任务相应的分区数据,这个过程叫复制阶段(copy phase)。一个Reduce任务并行多少个Map任务是由mapreduce.reduce.shuffle.parallelcopies参数决定(默认5)。

由于网络问题,Reduce任务无法获取数据时,会以指数退让(exponential backoff)的方式重试,超时时间由mapreduce.reduce.shuffle.connect.timeout设置(默认180000,单位毫秒),超时之后,Reduce任务标记为失败状态。

3. 中间输出结果的合并与溢出

Reduce任务也需要对多个Map任务的输出结果进行合并,过程如上图,根据Map任务的输出数据的大小,可能将其复制到内存或磁盘。mapreduce.reduce.shuffle.input.buffer.percent属性配置了这个任务占用的缓存空间在堆栈空间中的占用比例(默认0.70)。

mapreduce.reduce.shuffle.merge.percent决定缓存溢出到磁盘的阈值(默认0.66),mapreduce.reduce.merge.inmem.threshold设置了Map任务在缓存溢出前能够保留在内存中的输出个数的阈值(默认1000),只要一个满足,输出数据都将会写到磁盘。

在收到Map任务输出数据后,Reduce任务进入合并(merge)或排序(sort)阶段。同时合并的文件流的数量由mapreduce.task.io.sort.factor属性决定(默认10)。

Map任务输出数据的所有压缩操作,在合并时都会在内存中进行解压缩操作。

借鉴:https://blog.csdn.net/u013980127/article/details/52807360

链接:https://blog.csdn.net/u012151684/article/details/72589302

最新文章

  1. thinkphp3.2和phpexcel导入
  2. IE7浏览器窗口大小改变事件执行多次bug(转)
  3. mac 安装nginx
  4. springmvc json字符串转化成json对象
  5. C# 使用Conditional特性而不是#if条件编译
  6. oracle中删除表中某字段出现重复的信息 保留其中一条
  7. 对ASM存储管理的一些初步理解记录
  8. Android自定义progressBar
  9. Eclipse远程调试(远程服务器端监听)
  10. 控制台打印出event对象时,对象里面的currentTarget为null
  11. Sqlite 学习记录
  12. Firebird数据库相关备忘录
  13. .net mvc HtmlHelper扩展使用
  14. 【STM32】STM32 GPIO模式理解
  15. 记录一次MVC3升级MVC4遇到的问题
  16. (heap)239. Sliding Window Maximum
  17. Android Studio Build选项的功能
  18. Java如何根据IP获取当前定位
  19. split host
  20. CarbonData-1:common

热门文章

  1. 编写Postgres扩展之二:类型和运算符
  2. UI5-技术篇-SAP UI5数据表进行了比较:sap.m.Table与sap.ui.table.Table
  3. 什么是软件工具开发包(SDK)
  4. testlink关联redmine设置
  5. C#一些不太熟悉的类——扩展学习
  6. 使用Wireshark对手机抓包设置说明
  7. jquery-deferred应用
  8. webpack多页面打包配置
  9. MySQL进阶18- 存储过程- 创建语句-参数模式(in/out/inout-对应三个例子) -调用语法-delimiter 结束标记&#39;$&#39;- 删除/查看/修改-三个练习
  10. java UDP 通信:服务端与客服端