mapreduce流程
1、数据底层存储
将所要存储的文件进行分块存储,每块默认128M,不够128M的部分单独成一块,存储在节点上将所要存储的文件进行分块存储,每块默认128M,不够128M的部分单独成一块,存储在节点上
2、计算切片大小,进行逻辑划分,根据切片的个数来决定maptask个数,切片最大不会超过128*1.1M
3、maptask执行
利用FileInputFormat加载文件,通过流的方式将磁盘中的文件加载到内存中,是通过它的实现类TextInputFormat将中的RecordReader来实现按行读取,RecordReader这个抽象类默认使用LineRecordReader,返回了一个(k,v)
每个maptask通过job.setMapperClass(Map.class) 指定所运行的Mapper 不指定即使用默认的
Map.class继承Mapper类,重写map方法来一次读取一行数据,实际是通过调用run()方法来实现maptask的运行
进入shuffle
4、collector
maptask通过context.write(k,v)将一行数据通过collector传输到环形缓冲区中
5、环形缓冲区
环形缓冲区中将读取来的数据放置在byte[]上,包含元数据以及原始数据
元数据包含四点信息:描述原始数据的存储位置,之后获取数据方便
1)分区编号 对原始数据利用相关分区原则赋予分区编号
2)每一条原始数据的key的起始位置 为了方便获取key
3)每一条原始数据v的起始位置 为了方便获取value
4)v的长度: key的长度可以通过v的起始位置-key的起始位置来得到,所以只需要value的长度即可
因为原始数据的长度不确定,排序进行交换时不方便,所以记录了元数据,固定长度16,排序后只需交换元数据的位置即可
在环形缓冲区中,设置了分界线equator,用来划分元数据与原始数据,元数据从分界线依次向左存储,原始数据从分界线依次向右存储。
原始数据分割线向右部分存满可接着从头开始存入,同理,元数据分割线向左存满后可从尾开始存入,因此形成了一个环状结构
环形缓冲区默认大小100M,当元数据和原始数据存储达到80%时,此时将从内存向磁盘进行溢写
如果此时20%预留空间写满,而80%还没有释放,将会出现阻塞
留出的20%是为了可以继续接收maptask的写入,80%释放的过程中,缓冲区内部元数据存储的元素将向原始数据的第一个元素的位置移动,形成一个新的分界线
当满足溢写条件时,利用快速排序,先根据分区进行排序,然后每个分区内部根据自定义的规则进行排序
如果有combiner,在溢写到磁盘前,对数据进行聚合优化
6、溢写
溢写时,磁盘中会生成分配对应的的spill,spill中会将数据分区存储,最后没有满足80%的数据,会通过flush存入spill中
数据读取完成后,将相同分区中的数据归并(根据元数据的分区编号),同时根据key值进行两两归并排序,排序后如果想要使用优化,执行combiner
最终归并为一个文件,此时一个maptask执行完成
7、MRAPPMaster
是用来监控maptask 以及reducetask的状态以及进度的,只要一个maptask执行完成就会启动reducetask
8、fetch
reducetask执行的第一步是将maptask中的最终归并的文件拉取到reduce的本地
n个maptask生成了n个溢写最终归并的文件,此时fetch将多个归并后的文件中相同的分区抓取出来,默认同时启动5个进程(mapreduce.reduce.shuffle.parallelcopies),即同时可抓取5个
将抓取到的文件进行两两归并以及排序处理(规则是自定义的)
此时相同key值得数据就全部放在了一起,
8、分组
根据定义的分组条件分组(默认的是根据所有的key值分组),每分好一组就进入reduce中
shuffle结束
9、reducetask执行
每一个分区对应一个reducetask
每个reducetask通过job.setReducerClass(Reduce.class); 指定所运行的Reducer,不指定即使用默认的
Reduce.class继承Reducer类,重写reduce方法来一次读取一组数据,实际是通过调用run()方法来实现reducetask的运行
10、collector
reducetask通过context.write(k,v)一次输出一组数据,通过collector
11、内存的缓冲区
collector将获取到的数据写入到内存的缓冲区中,缓冲区分配给每个reducetask默认大小1024M(mapreduce.reduce.memory.mb)
如果 map 结果文件相当小,则通过collector直接复制到内存缓冲区内存中,此时分配的缓冲区大小默认是0.7(mapreduce.reduce.shuffle.input.buffer.percent)
如果缓冲区大小达到reduce阈值默认大小0.66(mapreduce.reduce.shuffle.merge.percent)或者文件个数达到map的默认输出阈值1000(mapreduce.reduce.merge.inmem.threshold)
12、写入到磁盘
当内存缓冲区中满足了溢出条件,或者手动flush之后
加载FileOutputFormat,通过流的方式将内存中的文件读取到磁盘,通过实现类TextOutputFormat中的RecordWriter来按按行输出,LineRecordWriter实现按行输出结果
生成文件中包含
_SUCCESS 执行成功为空
part-r-5位数的编号