补:combiner函数会使map的输出结果更为紧凑
reduce的数量与map无关,与map的分区数量有关
shuffle:将map输出传给reduce的过程
shuffle洗牌 执行流程
InputFormat–>InputSplit
–>map函数(mapper)
–>环形缓冲区
写入环形内存缓冲区
因为频繁的磁盘I/O操作会严重的降低效率,
因此“中间结果”不会立马写入磁盘,而是优先存储到map节点的“环形内存缓冲区”,
并做一些预排序以提高效率,当写入的数据量达到预先设置的阙值后便会执行一次I/O操作
将数据写入到磁盘。每个map任务都会分配一个环形内存缓冲区,
用于存储map任务输出的键值对(默认大小100MB,mapreduce.task.io.sort.mb调整)
-->partition(分区) 默认hashpartition分区
-->sort(排序)
每个分区中对其中的键值对按键进行sort排序,具体是将数据按照partition和key两个关键字进行排序,
排序结果为缓冲区内的数据按照partition为单位聚集在一起,
同一个partition内的数据按照key有序
-->spill to disk(溢写至此磁盘)
一旦缓冲区内容达到阀值(mapreduce.map.io.sort.spill.percent,默认0.80,或者80%),
就会会锁定这80%的内存,排序完成后会创建一个溢出写文件(临时文件),
然后开启一个后台线程把这部分数据以一个临时文件的方式溢出写(spill)到本地磁盘中
剩余的20%的内存在此期间可以继续写入map输出的键值对。
溢出写过程按轮询方式将缓冲区中的内容写到mapreduce.cluster.local.dir属性指定的目录中
80%到本地磁盘,20%到缓冲区
–>merge(合并)
合并merge
当一个map task处理的数据很大,以至于超过缓冲区内存时,就会生成多个spill文件。
此时就需要对同一个map任务产生的多个spill文件进行合并生成最终的一个已分区且已排序的大文件。
配置属性mapreduce.task.io.sort.factor控制着一次最多能合并多少流,默认值是10。
溢出写文件合并完毕Reduce拉取后,Map将删除所有的临时溢出写文件,并告知NodeManager任务已完成,
-->存储在maptask节点的本地(本地存储)
———————————————————map端的shuffle结束———————————————————————————————
-->fetch(通过http协议拉取map端的输出结果,按照partition)
只要其中一个MapTask完成,ReduceTask就开始复制它的输出
-->merge(合并)将来自不同节点的map输出数据,合并成一个大的文件,供reduce使用;
压缩:在写磁盘的时候采用压缩的方式将map的输出结果进行压缩是一个减少网络开销的有效方法
并减少传给reducer的数据量。默认情况下,输出是不压缩的(将mapreduce.map.output.compress设置为true即可启动)
-->reduce函数(相同的key2调用一次reduce函数)
Reduce进程启动一些数据copy线程,通过HTTP方式请求MapTask所在的NodeManager以获取输出文件
NodeManager需要为分区文件运行reduce任务。
并且reduce任务需要集群上若干个map任务的map输出作为其特殊的分区文件。
而每个map任务的完成时间可能不同,因此只要有一个任务完成,reduce任务就开始复制其输出。
reduce任务有少量复制线程,因此能够并行取得map输出。默认线程数为5,
但这个默认值可以通过mapreduce.reduce.shuffle.parallelcopies属性进行设置
当一个reduce任务完成全部的复制和排序后,就会针对已根据键排好序的Key构造对应的
Value迭代器。这时就要用到分组,默认的根据键分组,
自定义的可是使用 job.setGroupingComparatorClass()方法设置分组函数类。
对于默认分组来说,只要这个比较器比较的两个Key相同,它们就属于同一组,它们的 Value就会放在一个Value迭代器,
而这个迭代器的Key使用属于同一个组的所有Key的第一个Key。
在reduce阶段,reduce()方法的输入是所有的Key和它的Value迭代器。
-->output输出
此阶段的输出直接写到输出文件系统,一般为HDFS。如果采用HDFS,
由于NodeManager也运行数据节点,所以第一个块副本将被写到本地磁盘
map->环形缓冲区->分区->整理->写到本地-合并->reduce读取
上图有4个map,一个reduce用来计算他们的1个分区
reducer如何知道哪台机器要获得reducer输出呢?
map任务成功完成后,它们会使用心跳机制通知它们的application master。