一、Mapreduce原理分析
1.1maptask运行机制
(1)首先,读取数据组件Inputformat(默认为TextInputFormat)会通过getsplit()方法对对应目录中的文件进行逻辑切片,默认128M,一个切片对应一个maptask。
(2)切分为切片之后,由RecordReader对象(默认为LineRecorder)进行读取,一次读取一行数据,返回<key,value>key为LongWritable类型,代表数据的偏移量,value为Text类型
代表字符串文本。
(3)之后调用用户写的Mapper类中的map函数,默认每读取一行调用一次。
(4)之后通过context.write(key,value)方法对结果进行map阶段的输出,输出的数据进入环形缓冲区,环形缓冲区中的数据按分区排列。(默认对key进行hash后%reduce的
数量,也可实现partitioner接口,自定义分区逻辑)
(5)环形缓冲区默认大小为100M,默认溢写比例为80%,及当数据达到缓冲区大小的80%后会启动溢写线程,锁定这部分空间,并对分区内数据进行快速排序。
(6)若配置过Combiner,则会对相同key的value进行聚合,以便减小数据量,减轻网络传输开销。
(7)最后如果有多个溢写文件,会进行一个归并排序,确保一个maptask对应一个磁盘文件。
1.2MapTask的并行度
我们知道,hdfs默认一个block大小为128M,split默认切片大小默认也是128M,这是一种巧合吗?
假设有一个300M的文件,我们按照1)分片大小100M ,2)分片大小128M进行思考
这是第一种情况,由于hdfs默认块是128M,假如split大小为100M,可以看出,第二个MapTask要想操作第二个分片需要跨机器到datanode1上去拉去数据,数据跨网络传输影响性能,
移动计算比移动数据更重要!!
再看看第二种情况
若split大小保持和block大小一致,则很好的解决了以上的问题。
split的数量则为maptask的并行度,那么并行度越高越好吗?答案是否定的,这里有一个比例是1.1,若文件大小大于128M但是小于128M*1.1,则会被当成一个切片对待。并行度高也会消耗资源。
二、ReduceTask原理分析
2.1ReduceTask运行机制
ReduceTask大概分成三个阶段:copy、sort,reduce。
copy阶段会启用一些数据copy线程(fetcher)请求maptask请求属于自己分区的文件。
Merge阶段这里的merge如map端的merge动作,只是数组中存放的是不同map端copy来的数 值。Copy过来的数据会先放入内存缓冲区中,这里的缓冲区大小要比map端的更为灵活。merge 有三种形式:内存到内存;内存到磁盘;磁盘到磁盘。默认情况下第一种形式不启用。当内存中的 数据量到达一定阈值,就启动内存到磁盘的merge。与map 端类似,这也是溢写的过程,这个过 程中如果你设置有Combiner,也是会启用的,然后在磁盘中生成了众多的溢写文件。第二种 merge方式一直在运行,直到没有map端的数据时才结束,然后启动第三种磁盘到磁盘的merge 方式生成最终的文件。
合并排序。把分散的数据合并成一个大的数据后,还会再对合并后的数据排序。 对排序后的键值对调用reduce方法,键相等的键值对调用一次reduce方法,每次调用会产生零个 或者多个键值对,最后把这些输出的键值对写入到HDFS文件中
2.2ReduceTask并行度
这里的并行度实在驱动类中手动设置的。一般要等于分区数